load-dropin.c 5.96 KB
Newer Older
1
/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
2

3 4 5 6 7 8
/***
  This file is part of systemd.

  Copyright 2010 Lennart Poettering

  systemd is free software; you can redistribute it and/or modify it
9 10
  under the terms of the GNU Lesser General Public License as published by
  the Free Software Foundation; either version 2.1 of the License, or
11 12 13 14 15
  (at your option) any later version.

  systemd is distributed in the hope that it will be useful, but
  WITHOUT ANY WARRANTY; without even the implied warranty of
  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 20 21
  along with systemd; If not, see <http://www.gnu.org/licenses/>.
***/

22 23 24 25
#include <dirent.h>
#include <errno.h>

#include "unit.h"
26
#include "load-dropin.h"
27
#include "log.h"
28
#include "strv.h"
29
#include "unit-name.h"
30 31
#include "conf-parser.h"
#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 37
        int r;

38 39 40
        assert(u);
        assert(path);

41 42 43 44 45 46 47 48 49 50
        /* The config directories are special, since the order of the
         * drop-ins matters */
        if (dependency < 0)  {
                r = strv_extend(strv, path);
                if (r < 0)
                        return log_oom();

                return 0;
        }

51 52
        d = opendir(path);
        if (!d) {
53 54 55 56 57 58
                if (errno == ENOENT)
                        return 0;

                return -errno;
        }

59 60 61 62 63 64 65 66 67 68 69 70 71 72
        for (;;) {
                struct dirent *de;
                union dirent_storage buf;
                _cleanup_free_ char *f = NULL;
                int k;

                k = readdir_r(d, &buf.de, &de);
                if (k != 0) {
                        log_error("Failed to read directory %s: %s", path, strerror(k));
                        return -k;
                }

                if (!de)
                        break;
73 74 75 76

                if (ignore_file(de->d_name))
                        continue;

77
                f = strjoin(path, "/", de->d_name, NULL);
78 79
                if (!f)
                        return log_oom();
80

81 82 83
                r = unit_add_dependency_by_name(u, dependency, de->d_name, f, true);
                if (r < 0)
                        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

Lennart Poettering's avatar
Lennart Poettering committed
93
        assert(u);
94 95 96
        assert(unit_path);
        assert(name);
        assert(suffix);
97

98
        path = strjoin(unit_path, "/", name, suffix, NULL);
99
        if (!path)
100
                return -ENOMEM;
101

Michal Schmidt's avatar
Michal Schmidt committed
102 103
        if (u->manager->unit_path_cache &&
            !set_get(u->manager->unit_path_cache, path))
104 105
                r = 0;
        else
106
                r = iterate_dir(u, path, dependency, strv);
107
        free(path);
108

109 110
        if (r < 0)
                return r;
111

Michal Schmidt's avatar
Michal Schmidt committed
112
        if (u->instance) {
113 114
                char *template;
                /* Also try the template dir */
115

116 117
                template = unit_name_template(name);
                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

Michal Schmidt's avatar
Michal Schmidt committed
126 127
                if (u->manager->unit_path_cache &&
                    !set_get(u->manager->unit_path_cache, path))
128 129
                        r = 0;
                else
130
                        r = iterate_dir(u, path, dependency, strv);
131
                free(path);
132

133 134 135
                if (r < 0)
                        return r;
        }
136

137 138
        return 0;
}
139

140
char **unit_find_dropin_paths(Unit *u) {
141 142
        Iterator i;
        char *t;
143
        _cleanup_strv_free_ char **strv = NULL;
144
        char **configs = NULL;
145 146
        int r;

147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176
        assert(u);

        SET_FOREACH(t, u->names, i) {
                char **p;

                STRV_FOREACH(p, u->manager->lookup_paths.unit_path) {
                        /* This loads the drop-in config snippets */
                        r = process_dir(u, *p, t, ".d", _UNIT_DEPENDENCY_INVALID, &strv);
                        if (r < 0)
                                return NULL;
                }
        }

        if (!strv_isempty(strv)) {
                r = conf_files_list_strv(&configs, ".conf", NULL, (const char**) strv);
                if (r < 0) {
                        log_error("Failed to get list of configuration files: %s", strerror(-r));
                        strv_free(configs);
                        return NULL;
                }

        }

        return configs;
}

int unit_load_dropin(Unit *u) {
        Iterator i;
        char *t, **f;
        int r;
177 178 179 180

        assert(u);

        /* Load dependencies from supplementary drop-in directories */
181

Michal Schmidt's avatar
Michal Schmidt committed
182
        SET_FOREACH(t, u->names, i) {
183 184
                char **p;

Michal Schmidt's avatar
Michal Schmidt committed
185
                STRV_FOREACH(p, u->manager->lookup_paths.unit_path) {
186
                        r = process_dir(u, *p, t, ".wants", UNIT_WANTS, NULL);
187
                        if (r < 0)
188 189
                                return r;

190
                        r = process_dir(u, *p, t, ".requires", UNIT_REQUIRES, NULL);
191
                        if (r < 0)
192
                                return r;
193
                }
194 195
        }

196 197 198
        u->dropin_paths = unit_find_dropin_paths(u);
        if (! u->dropin_paths)
                return 0;
199

200
        STRV_FOREACH(f, u->dropin_paths) {
201 202 203
                r = config_parse(u->id, *f, NULL,
                                 UNIT_VTABLE(u)->sections, config_item_perf_lookup,
                                 (void*) load_fragment_gperf_lookup, false, u);
204
                if (r < 0)
205 206 207
                        return r;
        }

208 209
        u->dropin_mtime = now(CLOCK_REALTIME);

210 211
        return 0;
}