chiark / gitweb /
util: add a bit of syntactic sugar to run short code fragments with a different umask
[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 char **unit_find_dropin_paths(Unit *u) {
141         Iterator i;
142         char *t;
143         _cleanup_strv_free_ char **strv = NULL;
144         char **configs = NULL;
145         int r;
146
147         assert(u);
148
149         SET_FOREACH(t, u->names, i) {
150                 char **p;
151
152                 STRV_FOREACH(p, u->manager->lookup_paths.unit_path) {
153                         /* This loads the drop-in config snippets */
154                         r = process_dir(u, *p, t, ".d", _UNIT_DEPENDENCY_INVALID, &strv);
155                         if (r < 0)
156                                 return NULL;
157                 }
158         }
159
160         if (!strv_isempty(strv)) {
161                 r = conf_files_list_strv(&configs, ".conf", NULL, (const char**) strv);
162                 if (r < 0) {
163                         log_error("Failed to get list of configuration files: %s", strerror(-r));
164                         strv_free(configs);
165                         return NULL;
166                 }
167
168         }
169
170         return configs;
171 }
172
173 int unit_load_dropin(Unit *u) {
174         Iterator i;
175         char *t, **f;
176         _cleanup_strv_free_ char **strv = NULL;
177         int r;
178
179         assert(u);
180
181         /* Load dependencies from supplementary drop-in directories */
182
183         SET_FOREACH(t, u->names, i) {
184                 char **p;
185
186                 STRV_FOREACH(p, u->manager->lookup_paths.unit_path) {
187                         r = process_dir(u, *p, t, ".wants", UNIT_WANTS, NULL);
188                         if (r < 0)
189                                 return r;
190
191                         r = process_dir(u, *p, t, ".requires", UNIT_REQUIRES, NULL);
192                         if (r < 0)
193                                 return r;
194                 }
195         }
196
197         u->dropin_paths = unit_find_dropin_paths(u);
198         if (! u->dropin_paths)
199                 return 0;
200
201         STRV_FOREACH(f, u->dropin_paths) {
202                 r = config_parse(*f, NULL, UNIT_VTABLE(u)->sections, config_item_perf_lookup, (void*) load_fragment_gperf_lookup, false, u);
203                 if (r < 0)
204                         return r;
205         }
206
207         u->dropin_mtime = now(CLOCK_REALTIME);
208
209         return 0;
210 }