chiark / gitweb /
unit: allow extension of unit files with .d/*.conf drop-ins
[elogind.git] / src / core / load-dropin.c
1 /*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
2
3 /***
4   This file is part of systemd.
5
6   Copyright 2010 Lennart Poettering
7
8   systemd is free software; you can redistribute it and/or modify it
9   under the terms of the GNU Lesser General Public License as published by
10   the Free Software Foundation; either version 2.1 of the License, or
11   (at your option) any later version.
12
13   systemd is distributed in the hope that it will be useful, but
14   WITHOUT ANY WARRANTY; without even the implied warranty of
15   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16   Lesser General Public License for more details.
17
18   You should have received a copy of the GNU Lesser General Public License
19   along with systemd; If not, see <http://www.gnu.org/licenses/>.
20 ***/
21
22 #include <dirent.h>
23 #include <errno.h>
24
25 #include "unit.h"
26 #include "load-dropin.h"
27 #include "log.h"
28 #include "strv.h"
29 #include "unit-name.h"
30 #include "conf-parser.h"
31 #include "load-fragment.h"
32
33 static int load_dropin_config_file(Unit *u, const char *path) {
34         assert(u);
35         assert(path);
36
37         if (!endswith(path, ".conf"))
38                 return 0;
39
40         return config_parse(path, NULL, UNIT_VTABLE(u)->sections, config_item_perf_lookup, (void*) load_fragment_gperf_lookup, false, u);
41 }
42
43 static int iterate_dir(Unit *u, const char *path, UnitDependency dependency) {
44         _cleanup_closedir_ DIR *d = NULL;
45         int r;
46
47         assert(u);
48         assert(path);
49
50         d = opendir(path);
51         if (!d) {
52                 if (errno == ENOENT)
53                         return 0;
54
55                 return -errno;
56         }
57
58         for (;;) {
59                 struct dirent *de;
60                 union dirent_storage buf;
61                 _cleanup_free_ char *f = NULL;
62                 int k;
63
64                 k = readdir_r(d, &buf.de, &de);
65                 if (k != 0) {
66                         log_error("Failed to read directory %s: %s", path, strerror(k));
67                         return -k;
68                 }
69
70                 if (!de)
71                         break;
72
73                 if (ignore_file(de->d_name))
74                         continue;
75
76                 f = strjoin(path, "/", de->d_name, NULL);
77                 if (!f)
78                         return log_oom();
79
80                 if (dependency >= 0) {
81                         r = unit_add_dependency_by_name(u, dependency, de->d_name, f, true);
82                         if (r < 0)
83                                 log_error("Cannot add dependency %s to %s, ignoring: %s", de->d_name, u->id, strerror(-r));
84                 } else {
85                         r = load_dropin_config_file(u, f);
86                         if (r < 0)
87                                 log_error("Cannot load drop-in configuration file %s for %s, ignoring: %s", f, u->id, strerror(-r));
88                 }
89         }
90
91         return 0;
92 }
93
94 static int process_dir(Unit *u, const char *unit_path, const char *name, const char *suffix, UnitDependency dependency) {
95         int r;
96         char *path;
97
98         assert(u);
99         assert(unit_path);
100         assert(name);
101         assert(suffix);
102
103         path = strjoin(unit_path, "/", name, suffix, NULL);
104         if (!path)
105                 return -ENOMEM;
106
107         if (u->manager->unit_path_cache &&
108             !set_get(u->manager->unit_path_cache, path))
109                 r = 0;
110         else
111                 r = iterate_dir(u, path, dependency);
112         free(path);
113
114         if (r < 0)
115                 return r;
116
117         if (u->instance) {
118                 char *template;
119                 /* Also try the template dir */
120
121                 template = unit_name_template(name);
122                 if (!template)
123                         return -ENOMEM;
124
125                 path = strjoin(unit_path, "/", template, suffix, NULL);
126                 free(template);
127
128                 if (!path)
129                         return -ENOMEM;
130
131                 if (u->manager->unit_path_cache &&
132                     !set_get(u->manager->unit_path_cache, path))
133                         r = 0;
134                 else
135                         r = iterate_dir(u, path, dependency);
136                 free(path);
137
138                 if (r < 0)
139                         return r;
140         }
141
142         return 0;
143 }
144
145 int unit_load_dropin(Unit *u) {
146         Iterator i;
147         char *t;
148
149         assert(u);
150
151         /* Load dependencies from supplementary drop-in directories */
152
153         SET_FOREACH(t, u->names, i) {
154                 char **p;
155
156                 STRV_FOREACH(p, u->manager->lookup_paths.unit_path) {
157                         int r;
158
159                         r = process_dir(u, *p, t, ".wants", UNIT_WANTS);
160                         if (r < 0)
161                                 return r;
162
163                         r = process_dir(u, *p, t, ".requires", UNIT_REQUIRES);
164                         if (r < 0)
165                                 return r;
166
167                         /* This loads the drop-in config snippets */
168                         r = process_dir(u, *p, t, ".d", _UNIT_TYPE_INVALID);
169                         if (r < 0)
170                                 return r;
171                 }
172         }
173
174         return 0;
175 }