]> git.ipfire.org Git - thirdparty/systemd.git/blame - src/machine/image.c
machined: add new GetImage() bus call for retrieving the bus path for an image
[thirdparty/systemd.git] / src / machine / image.c
CommitLineData
cd61c3bf
LP
1/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
2
3/***
4 This file is part of systemd.
5
6 Copyright 2013 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 <sys/statfs.h>
23
24#include "strv.h"
25#include "utf8.h"
26#include "btrfs-util.h"
27#include "image.h"
28#include "bus-label.h"
29
c2ce6a3d
LP
30static const char image_search_path[] =
31 "/var/lib/container\0"
32 "/var/lib/machine\0";
33
cd61c3bf
LP
34Image *image_unref(Image *i) {
35 if (!i)
36 return NULL;
37
38 free(i->name);
39 free(i->path);
40 free(i);
41 return NULL;
42}
43
c2ce6a3d 44static int image_new(
cd61c3bf
LP
45 ImageType t,
46 const char *name,
47 const char *path,
48 bool read_only,
49 usec_t mtime,
c2ce6a3d
LP
50 usec_t btime,
51 Image **ret) {
cd61c3bf
LP
52
53 _cleanup_(image_unrefp) Image *i = NULL;
cd61c3bf 54
cd61c3bf
LP
55 assert(t >= 0);
56 assert(t < _IMAGE_TYPE_MAX);
57 assert(name);
c2ce6a3d 58 assert(ret);
cd61c3bf 59
c2ce6a3d 60 i = new0(Image, 1);
cd61c3bf
LP
61 if (!i)
62 return -ENOMEM;
63
64 i->type = t;
65 i->read_only = read_only;
66 i->mtime = mtime;
67 i->btime = btime;
68
69 i->name = strdup(name);
70 if (!i->name)
71 return -ENOMEM;
72
73 if (path) {
74 i->path = strdup(path);
75 if (!i->path)
76 return -ENOMEM;
77 }
78
c2ce6a3d 79 *ret = i;
cd61c3bf 80 i = NULL;
c2ce6a3d 81
cd61c3bf
LP
82 return 0;
83}
84
c2ce6a3d
LP
85static int image_make(int dfd, const char *name, const char *path, Image **ret) {
86 struct stat st;
cd61c3bf
LP
87 int r;
88
c2ce6a3d
LP
89 assert(dfd >= 0);
90 assert(name);
cd61c3bf 91
c2ce6a3d
LP
92 /* We explicitly *do* follow symlinks here, since we want to
93 * allow symlinking trees into /var/lib/container/, and treat
94 * them normally. */
cd61c3bf 95
c2ce6a3d
LP
96 if (fstatat(dfd, name, &st, 0) < 0)
97 return -errno;
cd61c3bf 98
c2ce6a3d 99 if (S_ISDIR(st.st_mode)) {
cd61c3bf 100
c2ce6a3d
LP
101 if (!ret)
102 return 1;
cd61c3bf 103
c2ce6a3d
LP
104 /* btrfs subvolumes have inode 256 */
105 if (st.st_ino == 256) {
106 _cleanup_close_ int fd = -1;
107 struct statfs sfs;
cd61c3bf 108
c2ce6a3d
LP
109 fd = openat(dfd, name, O_CLOEXEC|O_NOCTTY|O_DIRECTORY);
110 if (fd < 0)
111 return -errno;
cd61c3bf 112
c2ce6a3d
LP
113 if (fstatfs(fd, &sfs) < 0)
114 return -errno;
cd61c3bf 115
c2ce6a3d
LP
116 if (F_TYPE_EQUAL(sfs.f_type, BTRFS_SUPER_MAGIC)) {
117 usec_t btime = 0;
118 int ro;
cd61c3bf 119
c2ce6a3d 120 /* It's a btrfs subvolume */
cd61c3bf 121
c2ce6a3d
LP
122 ro = btrfs_subvol_is_read_only_fd(fd);
123 if (ro < 0)
124 return ro;
cd61c3bf 125
c2ce6a3d
LP
126 /* r = btrfs_subvol_get_btime(fd, &btime); */
127 /* if (r < 0) */
128 /* return r; */
129
130 r = image_new(IMAGE_SUBVOLUME,
131 name,
132 path,
133 ro,
134 0,
135 btime,
136 ret);
137 if (r < 0)
138 return r;
139
140 return 1;
cd61c3bf 141 }
c2ce6a3d 142 }
cd61c3bf 143
c2ce6a3d 144 /* It's just a normal directory. */
cd61c3bf 145
c2ce6a3d
LP
146 r = image_new(IMAGE_DIRECTORY,
147 name,
148 path,
149 false,
150 0,
151 0,
152 ret);
153 if (r < 0)
154 return r;
cd61c3bf 155
c2ce6a3d 156 return 1;
cd61c3bf 157
c2ce6a3d 158 } else if (S_ISREG(st.st_mode) && endswith(name, ".gpt")) {
cd61c3bf 159
c2ce6a3d 160 /* It's a GPT block device */
cd61c3bf 161
c2ce6a3d
LP
162 if (!ret)
163 return 1;
cd61c3bf 164
c2ce6a3d
LP
165 r = image_new(IMAGE_GPT,
166 name,
167 path,
168 !!(st.st_mode & 0111),
169 timespec_load(&st.st_mtim),
170 0,
171 ret);
172 if (r < 0)
173 return r;
cd61c3bf 174
c2ce6a3d
LP
175 return 1;
176 }
cd61c3bf 177
c2ce6a3d
LP
178 return 0;
179}
cd61c3bf 180
c2ce6a3d
LP
181int image_find(const char *name, Image **ret) {
182 const char *path;
183 int r;
cd61c3bf 184
c2ce6a3d 185 assert(name);
cd61c3bf 186
c2ce6a3d
LP
187 /* There are no images with invalid names */
188 if (!image_name_is_valid(name))
189 return 0;
cd61c3bf 190
c2ce6a3d
LP
191 NULSTR_FOREACH(path, image_search_path) {
192 _cleanup_closedir_ DIR *d = NULL;
cd61c3bf 193
c2ce6a3d
LP
194 d = opendir(path);
195 if (!d) {
196 if (errno == ENOENT)
197 continue;
cd61c3bf 198
c2ce6a3d
LP
199 return -errno;
200 }
cd61c3bf 201
c2ce6a3d
LP
202 r = image_make(dirfd(d), name, path, ret);
203 if (r == 0 || r == -ENOENT)
204 continue;
205 if (r < 0)
206 return r;
cd61c3bf 207
c2ce6a3d
LP
208 return 1;
209 }
210
211 return 0;
212};
213
214int image_discover(Hashmap *h) {
215 const char *path;
216 int r;
217
218 assert(h);
219
220 NULSTR_FOREACH(path, image_search_path) {
221 _cleanup_closedir_ DIR *d = NULL;
222 struct dirent *de;
223
224 d = opendir(path);
225 if (!d) {
226 if (errno == ENOENT)
227 return 0;
228
229 return -errno;
230 }
231
232 FOREACH_DIRENT_ALL(de, d, return -errno) {
233 _cleanup_(image_unrefp) Image *image = NULL;
234
235 if (!image_name_is_valid(de->d_name))
236 continue;
237
238 if (hashmap_contains(h, de->d_name))
239 continue;
240
241 r = image_make(dirfd(d), de->d_name, path, &image);
242 if (r == 0 || r == -ENOENT)
243 continue;
244 if (r < 0)
245 return r;
246
247 r = hashmap_put(h, image->name, image);
248 if (r < 0)
249 return r;
250
251 image = NULL;
cd61c3bf
LP
252 }
253 }
254
255 return 0;
256}
257
258void image_hashmap_free(Hashmap *map) {
259 Image *i;
260
261 while ((i = hashmap_steal_first(map)))
262 image_unref(i);
263
264 hashmap_free(map);
265}
266
267char *image_bus_path(const char *name) {
268 _cleanup_free_ char *e = NULL;
269
270 assert(name);
271
272 e = bus_label_escape(name);
273 if (!e)
274 return NULL;
275
276 return strappend("/org/freedesktop/machine1/image/", e);
277}
278
279static const char* const image_type_table[_IMAGE_TYPE_MAX] = {
280 [IMAGE_DIRECTORY] = "directory",
281 [IMAGE_SUBVOLUME] = "subvolume",
282 [IMAGE_GPT] = "gpt",
283};
284
285DEFINE_STRING_TABLE_LOOKUP(image_type, ImageType);