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