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