chiark / gitweb /
ac96d0f746836e8b25daca5457d4a1f4233834d5
[elogind.git] / load-fragment.c
1 /*-*- Mode: C; c-basic-offset: 8 -*-*/
2
3 #include <linux/oom.h>
4 #include <assert.h>
5 #include <errno.h>
6 #include <string.h>
7 #include <unistd.h>
8 #include <fcntl.h>
9
10 #include "unit.h"
11 #include "strv.h"
12 #include "conf-parser.h"
13 #include "load-fragment.h"
14 #include "log.h"
15 #include "ioprio.h"
16
17 static int config_parse_deps(
18                 const char *filename,
19                 unsigned line,
20                 const char *section,
21                 const char *lvalue,
22                 const char *rvalue,
23                 void *data,
24                 void *userdata) {
25
26         UnitDependency d = PTR_TO_UINT(data);
27         Unit *u = userdata;
28         char *w;
29         size_t l;
30         char *state;
31
32         assert(filename);
33         assert(lvalue);
34         assert(rvalue);
35
36         FOREACH_WORD(w, &l, rvalue, state) {
37                 char *t;
38                 int r;
39
40                 if (!(t = strndup(w, l)))
41                         return -ENOMEM;
42
43                 r = unit_add_dependency_by_name(u, d, t);
44                 free(t);
45
46                 if (r < 0)
47                         return r;
48         }
49
50         return 0;
51 }
52
53 static int config_parse_names(
54                 const char *filename,
55                 unsigned line,
56                 const char *section,
57                 const char *lvalue,
58                 const char *rvalue,
59                 void *data,
60                 void *userdata) {
61
62         Unit *u = userdata;
63         char *w;
64         size_t l;
65         char *state;
66
67         assert(filename);
68         assert(lvalue);
69         assert(rvalue);
70         assert(data);
71
72         FOREACH_WORD(w, &l, rvalue, state) {
73                 char *t;
74                 int r;
75                 Unit *other;
76
77                 if (!(t = strndup(w, l)))
78                         return -ENOMEM;
79
80                 other = manager_get_unit(u->meta.manager, t);
81
82                 if (other) {
83
84                         if (other != u) {
85
86                                 if (other->meta.load_state != UNIT_STUB) {
87                                         free(t);
88                                         return -EEXIST;
89                                 }
90
91                                 if ((r = unit_merge(u, other)) < 0) {
92                                         free(t);
93                                         return r;
94                                 }
95                         }
96
97                 } else {
98                         if ((r = unit_add_name(u, t)) < 0) {
99                                 free(t);
100                                 return r;
101                         }
102                 }
103
104                 free(t);
105         }
106
107         return 0;
108 }
109
110 static int config_parse_listen(
111                 const char *filename,
112                 unsigned line,
113                 const char *section,
114                 const char *lvalue,
115                 const char *rvalue,
116                 void *data,
117                 void *userdata) {
118
119         int r;
120         SocketPort *p;
121         Socket *s;
122
123         assert(filename);
124         assert(lvalue);
125         assert(rvalue);
126         assert(data);
127
128         s = (Socket*) data;
129
130         if (!(p = new0(SocketPort, 1)))
131                 return -ENOMEM;
132
133         if (streq(lvalue, "ListenFIFO")) {
134                 p->type = SOCKET_FIFO;
135
136                 if (!(p->path = strdup(rvalue))) {
137                         free(p);
138                         return -ENOMEM;
139                 }
140         } else {
141                 p->type = SOCKET_SOCKET;
142
143                 if ((r = socket_address_parse(&p->address, rvalue)) < 0) {
144                         log_error("[%s:%u] Failed to parse address value: %s", filename, line, rvalue);
145                         free(p);
146                         return r;
147                 }
148
149                 if (streq(lvalue, "ListenStream"))
150                         p->address.type = SOCK_STREAM;
151                 else if (streq(lvalue, "ListenDatagram"))
152                         p->address.type = SOCK_DGRAM;
153                 else {
154                         assert(streq(lvalue, "ListenSequentialPacket"));
155                         p->address.type = SOCK_SEQPACKET;
156                 }
157
158                 if (socket_address_family(&p->address) != AF_LOCAL && p->address.type == SOCK_SEQPACKET) {
159                         free(p);
160                         return -EPROTONOSUPPORT;
161                 }
162         }
163
164         p->fd = -1;
165         LIST_PREPEND(SocketPort, port, s->ports, p);
166
167         return 0;
168 }
169
170 static int config_parse_socket_bind(
171                 const char *filename,
172                 unsigned line,
173                 const char *section,
174                 const char *lvalue,
175                 const char *rvalue,
176                 void *data,
177                 void *userdata) {
178
179         int r;
180         Socket *s;
181
182         assert(filename);
183         assert(lvalue);
184         assert(rvalue);
185         assert(data);
186
187         s = (Socket*) data;
188
189         if ((r = parse_boolean(rvalue)) < 0) {
190                 log_error("[%s:%u] Failed to parse bind IPv6 only value: %s", filename, line, rvalue);
191                 return r;
192         }
193
194         s->bind_ipv6_only = r ? SOCKET_ADDRESS_IPV6_ONLY : SOCKET_ADDRESS_BOTH;
195
196         return 0;
197 }
198
199 static int config_parse_nice(
200                 const char *filename,
201                 unsigned line,
202                 const char *section,
203                 const char *lvalue,
204                 const char *rvalue,
205                 void *data,
206                 void *userdata) {
207
208         ExecContext *c = data;
209         int priority, r;
210
211         assert(filename);
212         assert(lvalue);
213         assert(rvalue);
214         assert(data);
215
216         if ((r = safe_atoi(rvalue, &priority)) < 0) {
217                 log_error("[%s:%u] Failed to parse nice priority: %s", filename, line, rvalue);
218                 return r;
219         }
220
221         if (priority < PRIO_MIN || priority >= PRIO_MAX) {
222                 log_error("[%s:%u] Nice priority out of range: %s", filename, line, rvalue);
223                 return -ERANGE;
224         }
225
226         c->nice = priority;
227         c->nice_set = false;
228
229         return 0;
230 }
231
232 static int config_parse_oom_adjust(
233                 const char *filename,
234                 unsigned line,
235                 const char *section,
236                 const char *lvalue,
237                 const char *rvalue,
238                 void *data,
239                 void *userdata) {
240
241         ExecContext *c = data;
242         int oa, r;
243
244         assert(filename);
245         assert(lvalue);
246         assert(rvalue);
247         assert(data);
248
249         if ((r = safe_atoi(rvalue, &oa)) < 0) {
250                 log_error("[%s:%u] Failed to parse OOM adjust value: %s", filename, line, rvalue);
251                 return r;
252         }
253
254         if (oa < OOM_DISABLE || oa > OOM_ADJUST_MAX) {
255                 log_error("[%s:%u] OOM adjust value out of range: %s", filename, line, rvalue);
256                 return -ERANGE;
257         }
258
259         c->oom_adjust = oa;
260         c->oom_adjust_set = true;
261
262         return 0;
263 }
264
265 static int config_parse_umask(
266                 const char *filename,
267                 unsigned line,
268                 const char *section,
269                 const char *lvalue,
270                 const char *rvalue,
271                 void *data,
272                 void *userdata) {
273
274         mode_t *m = data;
275         long l;
276         char *x = NULL;
277
278         assert(filename);
279         assert(lvalue);
280         assert(rvalue);
281         assert(data);
282
283         errno = 0;
284         l = strtol(rvalue, &x, 8);
285         if (!x || *x || errno) {
286                 log_error("[%s:%u] Failed to parse umask value: %s", filename, line, rvalue);
287                 return errno ? -errno : -EINVAL;
288         }
289
290         if (l < 0000 || l > 0777) {
291                 log_error("[%s:%u] umask value out of range: %s", filename, line, rvalue);
292                 return -ERANGE;
293         }
294
295         *m = (mode_t) l;
296         return 0;
297 }
298
299 static int config_parse_exec(
300                 const char *filename,
301                 unsigned line,
302                 const char *section,
303                 const char *lvalue,
304                 const char *rvalue,
305                 void *data,
306                 void *userdata) {
307
308         ExecCommand **e = data, *ee, *nce = NULL;
309         char **n;
310         char *w;
311         unsigned k;
312         size_t l;
313         char *state;
314
315         assert(filename);
316         assert(lvalue);
317         assert(rvalue);
318         assert(data);
319
320         k = 0;
321         FOREACH_WORD_QUOTED(w, l, rvalue, state)
322                 k++;
323
324         if (!(n = new(char*, k+1)))
325                 return -ENOMEM;
326
327         k = 0;
328         FOREACH_WORD_QUOTED(w, l, rvalue, state)
329                 if (!(n[k++] = strndup(w, l)))
330                         goto fail;
331
332         n[k] = NULL;
333
334         if (!n[0] || !path_is_absolute(n[0])) {
335                 log_error("[%s:%u] Invalid executable path in command line: %s", filename, line, rvalue);
336                 strv_free(n);
337                 return -EINVAL;
338         }
339
340         if (!(nce = new0(ExecCommand, 1)))
341                 goto fail;
342
343         nce->argv = n;
344         if (!(nce->path = strdup(n[0])))
345                 goto fail;
346
347         if (*e) {
348                 /* It's kinda important that we keep the order here */
349                 LIST_FIND_TAIL(ExecCommand, command, *e, ee);
350                 LIST_INSERT_AFTER(ExecCommand, command, *e, ee, nce);
351         } else
352                 *e = nce;
353
354         return 0;
355
356 fail:
357         for (; k > 0; k--)
358                 free(n[k-1]);
359         free(n);
360
361         free(nce);
362
363         return -ENOMEM;
364 }
365
366 static int config_parse_usec(
367                 const char *filename,
368                 unsigned line,
369                 const char *section,
370                 const char *lvalue,
371                 const char *rvalue,
372                 void *data,
373                 void *userdata) {
374
375         usec_t *usec = data;
376         unsigned long long u;
377         int r;
378
379         assert(filename);
380         assert(lvalue);
381         assert(rvalue);
382         assert(data);
383
384         if ((r = safe_atollu(rvalue, &u)) < 0) {
385                 log_error("[%s:%u] Failed to parse time value: %s", filename, line, rvalue);
386                 return r;
387         }
388
389         /* We actually assume the user configures seconds. Later on we
390          * might choose to support suffixes for time values, to
391          * configure bigger or smaller units */
392
393         *usec = u * USEC_PER_SEC;
394
395         return 0;
396 }
397
398 static int config_parse_service_type(
399                 const char *filename,
400                 unsigned line,
401                 const char *section,
402                 const char *lvalue,
403                 const char *rvalue,
404                 void *data,
405                 void *userdata) {
406
407         Service *s = data;
408
409         assert(filename);
410         assert(lvalue);
411         assert(rvalue);
412         assert(data);
413
414         if (streq(rvalue, "forking"))
415                 s->type = SERVICE_FORKING;
416         else if (streq(rvalue, "simple"))
417                 s->type = SERVICE_SIMPLE;
418         else {
419                 log_error("[%s:%u] Failed to parse service type: %s", filename, line, rvalue);
420                 return -EBADMSG;
421         }
422
423         return 0;
424 }
425
426 static int config_parse_service_restart(
427                 const char *filename,
428                 unsigned line,
429                 const char *section,
430                 const char *lvalue,
431                 const char *rvalue,
432                 void *data,
433                 void *userdata) {
434
435         Service *s = data;
436
437         assert(filename);
438         assert(lvalue);
439         assert(rvalue);
440         assert(data);
441
442         if (streq(rvalue, "once"))
443                 s->restart = SERVICE_ONCE;
444         else if (streq(rvalue, "on-success"))
445                 s->type = SERVICE_RESTART_ON_SUCCESS;
446         else if (streq(rvalue, "always"))
447                 s->type = SERVICE_RESTART_ALWAYS;
448         else {
449                 log_error("[%s:%u] Failed to parse service type: %s", filename, line, rvalue);
450                 return -EBADMSG;
451         }
452
453         return 0;
454 }
455
456 int 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
485 int 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) {
493
494         ExecOutput *o = data;
495
496         assert(filename);
497         assert(lvalue);
498         assert(rvalue);
499         assert(data);
500
501         if (streq(rvalue, "syslog"))
502                 *o = EXEC_SYSLOG;
503         else if (streq(rvalue, "null"))
504                 *o = EXEC_NULL;
505         else if (streq(rvalue, "syslog"))
506                 *o = EXEC_SYSLOG;
507         else if (streq(rvalue, "kernel"))
508                 *o = EXEC_KERNEL;
509         else {
510                 log_error("[%s:%u] Failed to parse log output: %s", filename, line, rvalue);
511                 return -EBADMSG;
512         }
513
514         return 0;
515 }
516
517 int config_parse_facility(
518                 const char *filename,
519                 unsigned line,
520                 const char *section,
521                 const char *lvalue,
522                 const char *rvalue,
523                 void *data,
524                 void *userdata) {
525
526         static const char * const table[LOG_NFACILITIES] = {
527                 [LOG_FAC(LOG_KERN)] = "kern",
528                 [LOG_FAC(LOG_USER)] = "user",
529                 [LOG_FAC(LOG_MAIL)] = "mail",
530                 [LOG_FAC(LOG_DAEMON)] = "daemon",
531                 [LOG_FAC(LOG_AUTH)] = "auth",
532                 [LOG_FAC(LOG_SYSLOG)] = "syslog",
533                 [LOG_FAC(LOG_LPR)] = "lpr",
534                 [LOG_FAC(LOG_NEWS)] = "news",
535                 [LOG_FAC(LOG_UUCP)] = "uucp",
536                 [LOG_FAC(LOG_CRON)] = "cron",
537                 [LOG_FAC(LOG_AUTHPRIV)] = "authpriv",
538                 [LOG_FAC(LOG_FTP)] = "ftp",
539                 [LOG_FAC(LOG_LOCAL0)] = "local0",
540                 [LOG_FAC(LOG_LOCAL1)] = "local1",
541                 [LOG_FAC(LOG_LOCAL2)] = "local2",
542                 [LOG_FAC(LOG_LOCAL3)] = "local3",
543                 [LOG_FAC(LOG_LOCAL4)] = "local4",
544                 [LOG_FAC(LOG_LOCAL5)] = "local5",
545                 [LOG_FAC(LOG_LOCAL6)] = "local6",
546                 [LOG_FAC(LOG_LOCAL7)] = "local7"
547         };
548
549         ExecOutput *o = data;
550         int i;
551
552         assert(filename);
553         assert(lvalue);
554         assert(rvalue);
555         assert(data);
556
557         for (i = 0; i < (int) ELEMENTSOF(table); i++)
558                 if (streq(rvalue, table[i])) {
559                         *o = LOG_MAKEPRI(i, LOG_PRI(*o));
560                         break;
561                 }
562
563         if (i >= (int) ELEMENTSOF(table)) {
564
565                 /* Second try, let's see if this is a number. */
566                 if (safe_atoi(rvalue, &i) >= 0 &&
567                     i >= 0 &&
568                     i < (int) ELEMENTSOF(table))
569                         *o = LOG_MAKEPRI(i, LOG_PRI(*o));
570                 else {
571                         log_error("[%s:%u] Failed to parse log output: %s", filename, line, rvalue);
572                         return -EBADMSG;
573                 }
574         }
575
576         return 0;
577 }
578
579 int config_parse_level(
580                 const char *filename,
581                 unsigned line,
582                 const char *section,
583                 const char *lvalue,
584                 const char *rvalue,
585                 void *data,
586                 void *userdata) {
587
588         static const char * const table[LOG_DEBUG+1] = {
589                 [LOG_EMERG] = "emerg",
590                 [LOG_ALERT] = "alert",
591                 [LOG_CRIT] = "crit",
592                 [LOG_ERR] = "err",
593                 [LOG_WARNING] = "warning",
594                 [LOG_NOTICE] = "notice",
595                 [LOG_INFO] = "info",
596                 [LOG_DEBUG] = "debug"
597         };
598
599         ExecOutput *o = data;
600         int i;
601
602         assert(filename);
603         assert(lvalue);
604         assert(rvalue);
605         assert(data);
606
607         for (i = 0; i < (int) ELEMENTSOF(table); i++)
608                 if (streq(rvalue, table[i])) {
609                         *o = LOG_MAKEPRI(LOG_FAC(*o), i);
610                         break;
611                 }
612
613         if (i >= LOG_NFACILITIES) {
614
615                 /* Second try, let's see if this is a number. */
616                 if (safe_atoi(rvalue, &i) >= 0 &&
617                     i >= 0 &&
618                     i < (int) ELEMENTSOF(table))
619                         *o = LOG_MAKEPRI(LOG_FAC(*o), i);
620                 else {
621                         log_error("[%s:%u] Failed to parse log output: %s", filename, line, rvalue);
622                         return -EBADMSG;
623                 }
624         }
625
626         return 0;
627 }
628
629 int config_parse_io_class(
630                 const char *filename,
631                 unsigned line,
632                 const char *section,
633                 const char *lvalue,
634                 const char *rvalue,
635                 void *data,
636                 void *userdata) {
637
638         static const char * const table[] = {
639                 [IOPRIO_CLASS_NONE] = NULL,
640                 [IOPRIO_CLASS_RT] = "realtime",
641                 [IOPRIO_CLASS_BE] = "best-effort",
642                 [IOPRIO_CLASS_IDLE] = "idle",
643         };
644
645         ExecContext *c = data;
646         int i;
647
648         assert(filename);
649         assert(lvalue);
650         assert(rvalue);
651         assert(data);
652
653         for (i = 0; i < (int) ELEMENTSOF(table); i++) {
654                 if (!table[i])
655                         continue;
656
657                 if (streq(rvalue, table[i])) {
658                         c->ioprio = IOPRIO_PRIO_VALUE(i, IOPRIO_PRIO_DATA(c->ioprio));
659                         break;
660                 }
661         }
662
663         if (i >= (int) ELEMENTSOF(table)) {
664
665                 /* Second try, let's see if this is a number. */
666                 if (safe_atoi(rvalue, &i) >= 0 &&
667                     i >= 0 &&
668                     i < (int) ELEMENTSOF(table) &&
669                     table[i])
670                         c->ioprio = IOPRIO_PRIO_VALUE(i, IOPRIO_PRIO_DATA(c->ioprio));
671                 else {
672                         log_error("[%s:%u] Failed to parse io priority: %s", filename, line, rvalue);
673                         return -EBADMSG;
674                 }
675         }
676
677         c->ioprio_set = true;
678
679         return 0;
680 }
681
682 int config_parse_io_priority(
683                 const char *filename,
684                 unsigned line,
685                 const char *section,
686                 const char *lvalue,
687                 const char *rvalue,
688                 void *data,
689                 void *userdata) {
690
691         ExecContext *c = data;
692         int i;
693
694         assert(filename);
695         assert(lvalue);
696         assert(rvalue);
697         assert(data);
698
699         if (safe_atoi(rvalue, &i) >= 0 &&
700             i >= 0 &&
701             i < IOPRIO_BE_NR)
702                 c->ioprio = IOPRIO_PRIO_VALUE(IOPRIO_PRIO_CLASS(c->ioprio), i);
703         else {
704                 log_error("[%s:%u] Failed to parse io priority: %s", filename, line, rvalue);
705                 return -EBADMSG;
706         }
707
708         c->ioprio_set = true;
709
710         return 0;
711 }
712
713 #define FOLLOW_MAX 8
714
715 static int open_follow(char **filename, FILE **_f, Set *names, char **_id) {
716         unsigned c = 0;
717         int fd, r;
718         FILE *f;
719         char *id = NULL;
720
721         assert(filename);
722         assert(*filename);
723         assert(_f);
724         assert(names);
725
726         /* This will update the filename pointer if the loaded file is
727          * reached by a symlink. The old string will be freed. */
728
729         for (;;) {
730                 char *target, *k, *name;
731
732                 if (c++ >= FOLLOW_MAX)
733                         return -ELOOP;
734
735                 path_kill_slashes(*filename);
736
737                 /* Add the file name we are currently looking at to
738                  * the names of this unit */
739                 name = file_name_from_path(*filename);
740                 if (!(id = set_get(names, name))) {
741
742                         if (!(id = strdup(name)))
743                                 return -ENOMEM;
744
745                         if ((r = set_put(names, id)) < 0) {
746                                 free(id);
747                                 return r;
748                         }
749                 }
750
751                 /* Try to open the file name, but don't if its a symlink */
752                 if ((fd = open(*filename, O_RDONLY|O_CLOEXEC|O_NOCTTY|O_NOFOLLOW)) >= 0)
753                         break;
754
755                 if (errno != ELOOP)
756                         return -errno;
757
758                 /* Hmm, so this is a symlink. Let's read the name, and follow it manually */
759                 if ((r = readlink_malloc(*filename, &target)) < 0)
760                         return r;
761
762                 k = file_in_same_dir(*filename, target);
763                 free(target);
764
765                 if (!k)
766                         return -ENOMEM;
767
768                 free(*filename);
769                 *filename = k;
770         }
771
772         if (!(f = fdopen(fd, "r"))) {
773                 r = -errno;
774                 assert(close_nointr(fd) == 0);
775                 return r;
776         }
777
778         *_f = f;
779         *_id = id;
780         return 0;
781 }
782
783 static int load_from_path(Unit *u, const char *path) {
784
785         static const char* const section_table[_UNIT_TYPE_MAX] = {
786                 [UNIT_SERVICE]   = "Service",
787                 [UNIT_TIMER]     = "Timer",
788                 [UNIT_SOCKET]    = "Socket",
789                 [UNIT_TARGET]    = "Target",
790                 [UNIT_DEVICE]    = "Device",
791                 [UNIT_MOUNT]     = "Mount",
792                 [UNIT_AUTOMOUNT] = "Automount",
793                 [UNIT_SNAPSHOT]  = "Snapshot"
794         };
795
796 #define EXEC_CONTEXT_CONFIG_ITEMS(context, section) \
797                 { "WorkingDirectory",       config_parse_path,            &(context).working_directory,                    section   }, \
798                 { "RootDirectory",          config_parse_path,            &(context).root_directory,                       section   }, \
799                 { "User",                   config_parse_string,          &(context).user,                                 section   }, \
800                 { "Group",                  config_parse_string,          &(context).group,                                section   }, \
801                 { "SupplementaryGroups",    config_parse_strv,            &(context).supplementary_groups,                 section   }, \
802                 { "Nice",                   config_parse_nice,            &(context),                                      section   }, \
803                 { "OOMAdjust",              config_parse_oom_adjust,      &(context),                                      section   }, \
804                 { "IOPriority",             config_parse_io_priority,     &(context),                                      section   }, \
805                 { "IOSchedulingClass",      config_parse_io_class,        &(context),                                      section   }, \
806                 { "UMask",                  config_parse_umask,           &(context).umask,                                section   }, \
807                 { "Environment",            config_parse_strv,            &(context).environment,                          section   }, \
808                 { "Output",                 config_parse_output,          &(context).output,                               section   }, \
809                 { "SyslogIdentifier",       config_parse_string,          &(context).syslog_identifier,                    section   }, \
810                 { "SyslogFacility",         config_parse_facility,        &(context).syslog_priority,                      section   }, \
811                 { "SyslogLevel",            config_parse_level,           &(context).syslog_priority,                      section   }
812
813         const ConfigItem items[] = {
814                 { "Names",                  config_parse_names,           u,                                               "Meta"    },
815                 { "Description",            config_parse_string,          &u->meta.description,                            "Meta"    },
816                 { "Requires",               config_parse_deps,            UINT_TO_PTR(UNIT_REQUIRES),                      "Meta"    },
817                 { "SoftRequires",           config_parse_deps,            UINT_TO_PTR(UNIT_SOFT_REQUIRES),                 "Meta"    },
818                 { "Wants",                  config_parse_deps,            UINT_TO_PTR(UNIT_WANTS),                         "Meta"    },
819                 { "Requisite",              config_parse_deps,            UINT_TO_PTR(UNIT_REQUISITE),                     "Meta"    },
820                 { "SoftRequisite",          config_parse_deps,            UINT_TO_PTR(UNIT_SOFT_REQUISITE),                "Meta"    },
821                 { "Conflicts",              config_parse_deps,            UINT_TO_PTR(UNIT_CONFLICTS),                     "Meta"    },
822                 { "Before",                 config_parse_deps,            UINT_TO_PTR(UNIT_BEFORE),                        "Meta"    },
823                 { "After",                  config_parse_deps,            UINT_TO_PTR(UNIT_AFTER),                         "Meta"    },
824                 { "RecursiveStop",          config_parse_bool,            &u->meta.recursive_stop,                         "Meta"    },
825                 { "StopWhenUnneeded",       config_parse_bool,            &u->meta.stop_when_unneeded,                     "Meta"    },
826
827                 { "PIDFile",                config_parse_path,            &u->service.pid_file,                            "Service" },
828                 { "ExecStartPre",           config_parse_exec,            u->service.exec_command+SERVICE_EXEC_START_PRE,  "Service" },
829                 { "ExecStart",              config_parse_exec,            u->service.exec_command+SERVICE_EXEC_START,      "Service" },
830                 { "ExecStartPost",          config_parse_exec,            u->service.exec_command+SERVICE_EXEC_START_POST, "Service" },
831                 { "ExecReload",             config_parse_exec,            u->service.exec_command+SERVICE_EXEC_RELOAD,     "Service" },
832                 { "ExecStop",               config_parse_exec,            u->service.exec_command+SERVICE_EXEC_STOP,       "Service" },
833                 { "ExecStopPost",           config_parse_exec,            u->service.exec_command+SERVICE_EXEC_STOP_POST,  "Service" },
834                 { "RestartSec",             config_parse_usec,            &u->service.restart_usec,                        "Service" },
835                 { "TimeoutSec",             config_parse_usec,            &u->service.timeout_usec,                        "Service" },
836                 { "Type",                   config_parse_service_type,    &u->service,                                     "Service" },
837                 { "Restart",                config_parse_service_restart, &u->service,                                     "Service" },
838                 EXEC_CONTEXT_CONFIG_ITEMS(u->service.exec_context, "Service"),
839
840                 { "ListenStream",           config_parse_listen,          &u->socket,                                      "Socket"  },
841                 { "ListenDatagram",         config_parse_listen,          &u->socket,                                      "Socket"  },
842                 { "ListenSequentialPacket", config_parse_listen,          &u->socket,                                      "Socket"  },
843                 { "ListenFIFO",             config_parse_listen,          &u->socket,                                      "Socket"  },
844                 { "BindIPv6Only",           config_parse_socket_bind,     &u->socket,                                      "Socket"  },
845                 { "Backlog",                config_parse_unsigned,        &u->socket.backlog,                              "Socket"  },
846                 { "BindToDevice",           config_parse_bindtodevice,    &u->socket,                                      "Socket"  },
847                 { "ExecStartPre",           config_parse_exec,            u->socket.exec_command+SOCKET_EXEC_START_PRE,    "Socket"  },
848                 { "ExecStartPost",          config_parse_exec,            u->socket.exec_command+SOCKET_EXEC_START_POST,   "Socket"  },
849                 { "ExecStopPre",            config_parse_exec,            u->socket.exec_command+SOCKET_EXEC_STOP_PRE,     "Socket"  },
850                 { "ExecStopPost",           config_parse_exec,            u->socket.exec_command+SOCKET_EXEC_STOP_POST,    "Socket"  },
851                 EXEC_CONTEXT_CONFIG_ITEMS(u->socket.exec_context, "Socket"),
852
853                 EXEC_CONTEXT_CONFIG_ITEMS(u->automount.exec_context, "Automount"),
854
855                 { NULL, NULL, NULL, NULL }
856         };
857
858 #undef EXEC_CONTEXT_CONFIG_ITEMS
859
860         const char *sections[3];
861         char *k;
862         int r;
863         Set *symlink_names;
864         FILE *f;
865         char *filename, *id;
866
867         sections[0] = "Meta";
868         sections[1] = section_table[u->meta.type];
869         sections[2] = NULL;
870
871         if (!(symlink_names = set_new(string_hash_func, string_compare_func)))
872                 return -ENOMEM;
873
874         /* Instead of opening the path right away, we manually
875          * follow all symlinks and add their name to our unit
876          * name set while doing so */
877         if (!(filename = path_make_absolute(path, unit_path()))) {
878                 r = -ENOMEM;
879                 goto finish;
880         }
881
882         if ((r = open_follow(&filename, &f, symlink_names, &id)) < 0) {
883                 if (r == -ENOENT)
884                         r = 0; /* returning 0 means: no suitable config file found */
885
886                 goto finish;
887         }
888
889         /* Now, parse the file contents */
890         r = config_parse(filename, f, sections, items, u);
891         if (r < 0)
892                 goto finish;
893
894         /* Let's try to add in all symlink names we found */
895         while ((k = set_steal_first(symlink_names))) {
896                 if ((r = unit_add_name(u, k)) < 0)
897                         goto finish;
898
899
900                 if (id == k)
901                         unit_choose_id(u, id);
902                 free(k);
903         }
904
905
906         free(u->meta.load_path);
907         u->meta.load_path = filename;
908         filename = NULL;
909
910         r = 1; /* returning 1 means: suitable config file found and loaded */
911
912 finish:
913         while ((k = set_steal_first(symlink_names)))
914                 free(k);
915         set_free(symlink_names);
916         free(filename);
917
918         return r;
919 }
920
921 int unit_load_fragment(Unit *u) {
922         int r = 0;
923         ExecContext *c;
924
925         assert(u);
926         assert(u->meta.load_state == UNIT_STUB);
927
928         if (u->meta.load_path)
929                 r = load_from_path(u, u->meta.load_path);
930         else {
931                 Iterator i;
932                 char *t;
933
934                 /* Try to find a name we can load this with */
935                 SET_FOREACH(t, u->meta.names, i)
936                         if ((r = load_from_path(u, t)) != 0)
937                                 return r;
938         }
939
940         if (u->meta.type == UNIT_SOCKET)
941                 c = &u->socket.exec_context;
942         else if (u->meta.type == UNIT_SERVICE)
943                 c = &u->service.exec_context;
944         else
945                 c = NULL;
946
947         if (r >= 0 && c &&
948             (c->output == EXEC_KERNEL || c->output == EXEC_SYSLOG)) {
949                 int k;
950
951                 /* If syslog or kernel logging is requested, make sure
952                  * our own logging daemon is run first. */
953
954                 if ((k = unit_add_dependency_by_name(u, UNIT_AFTER, SPECIAL_LOGGER_SOCKET)) < 0)
955                         return k;
956
957                 if ((k = unit_add_dependency_by_name(u, UNIT_REQUIRES, SPECIAL_LOGGER_SOCKET)) < 0)
958                         return k;
959         }
960
961         return r;
962 }