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