chiark / gitweb /
7a17baaf8930359b1f8be1a3eb654fff99aa368a
[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 #include "conf-files.h"
33
34 static int iterate_dir(
35                 Unit *u,
36                 const char *path,
37                 UnitDependency dependency,
38                 char ***strv) {
39
40         _cleanup_closedir_ DIR *d = NULL;
41         int r;
42
43         assert(u);
44         assert(path);
45
46         /* The config directories are special, since the order of the
47          * drop-ins matters */
48         if (dependency < 0)  {
49                 r = strv_extend(strv, path);
50                 if (r < 0)
51                         return log_oom();
52
53                 return 0;
54         }
55
56         d = opendir(path);
57         if (!d) {
58                 if (errno == ENOENT)
59                         return 0;
60
61                 log_error("Failed to open directory %s: %m", path);
62                 return -errno;
63         }
64
65         for (;;) {
66                 struct dirent *de;
67                 _cleanup_free_ char *f = NULL;
68
69                 errno = 0;
70                 de = readdir(d);
71                 if (!de && errno != 0)
72                         return log_error_errno(errno, "Failed to read directory %s: %m", path);
73
74                 if (!de)
75                         break;
76
77                 if (ignore_file(de->d_name))
78                         continue;
79
80                 f = strjoin(path, "/", de->d_name, NULL);
81                 if (!f)
82                         return log_oom();
83
84                 r = unit_add_dependency_by_name(u, dependency, de->d_name, f, true);
85                 if (r < 0)
86                         log_error_errno(r, "Cannot add dependency %s to %s, ignoring: %m", de->d_name, u->id);
87         }
88
89         return 0;
90 }
91
92 static int process_dir(
93                 Unit *u,
94                 const char *unit_path,
95                 const char *name,
96                 const char *suffix,
97                 UnitDependency dependency,
98                 char ***strv) {
99
100         _cleanup_free_ char *path = NULL;
101
102         assert(u);
103         assert(unit_path);
104         assert(name);
105         assert(suffix);
106
107         path = strjoin(unit_path, "/", name, suffix, NULL);
108         if (!path)
109                 return log_oom();
110
111         if (!u->manager->unit_path_cache || set_get(u->manager->unit_path_cache, path))
112                 iterate_dir(u, path, dependency, strv);
113
114         if (u->instance) {
115                 _cleanup_free_ char *template = NULL, *p = NULL;
116                 /* Also try the template dir */
117
118                 template = unit_name_template(name);
119                 if (!template)
120                         return log_oom();
121
122                 p = strjoin(unit_path, "/", template, suffix, NULL);
123                 if (!p)
124                         return log_oom();
125
126                 if (!u->manager->unit_path_cache || set_get(u->manager->unit_path_cache, p))
127                         iterate_dir(u, p, dependency, strv);
128         }
129
130         return 0;
131 }
132
133 char **unit_find_dropin_paths(Unit *u) {
134         _cleanup_strv_free_ char **strv = NULL;
135         char **configs = NULL;
136         Iterator i;
137         char *t;
138         int r;
139
140         assert(u);
141
142         SET_FOREACH(t, u->names, i) {
143                 char **p;
144
145                 STRV_FOREACH(p, u->manager->lookup_paths.unit_path)
146                         process_dir(u, *p, t, ".d", _UNIT_DEPENDENCY_INVALID, &strv);
147         }
148
149         if (strv_isempty(strv))
150                 return NULL;
151
152         r = conf_files_list_strv(&configs, ".conf", NULL, (const char**) strv);
153         if (r < 0) {
154                 log_error_errno(r, "Failed to get list of configuration files: %m");
155                 strv_free(configs);
156                 return NULL;
157         }
158
159         return configs;
160 }
161
162 int unit_load_dropin(Unit *u) {
163         Iterator i;
164         char *t, **f;
165
166         assert(u);
167
168         /* Load dependencies from supplementary drop-in directories */
169
170         SET_FOREACH(t, u->names, i) {
171                 char **p;
172
173                 STRV_FOREACH(p, u->manager->lookup_paths.unit_path) {
174                         process_dir(u, *p, t, ".wants", UNIT_WANTS, NULL);
175                         process_dir(u, *p, t, ".requires", UNIT_REQUIRES, NULL);
176                 }
177         }
178
179         u->dropin_paths = unit_find_dropin_paths(u);
180         if (!u->dropin_paths)
181                 return 0;
182
183         STRV_FOREACH(f, u->dropin_paths) {
184                 config_parse(u->id, *f, NULL,
185                              UNIT_VTABLE(u)->sections,
186                              config_item_perf_lookup, load_fragment_gperf_lookup,
187                              false, false, false, u);
188         }
189
190         u->dropin_mtime = now(CLOCK_REALTIME);
191
192         return 0;
193 }