chiark / gitweb /
24c8ac1d13bf4ae4ae211ddd7ee3da74647c5ce2
[elogind.git] / src / import / import-util.c
1 /*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
2
3 /***
4   This file is part of systemd.
5
6   Copyright 2015 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 "util.h"
23 #include "strv.h"
24 #include "copy.h"
25 #include "btrfs-util.h"
26 #include "import-util.h"
27
28 #define FILENAME_ESCAPE "/.#\"\'"
29
30 bool http_etag_is_valid(const char *etag) {
31         if (!endswith(etag, "\""))
32                 return false;
33
34         if (!startswith(etag, "\"") && !startswith(etag, "W/\""))
35                 return false;
36
37         return true;
38 }
39
40 int import_find_old_etags(const char *url, const char *image_root, int dt, const char *prefix, const char *suffix, char ***etags) {
41         _cleanup_free_ char *escaped_url = NULL;
42         _cleanup_closedir_ DIR *d = NULL;
43         _cleanup_strv_free_ char **l = NULL;
44         struct dirent *de;
45         int r;
46
47         assert(url);
48         assert(etags);
49
50         if (!image_root)
51                 image_root = "/var/lib/machines";
52
53         escaped_url = xescape(url, FILENAME_ESCAPE);
54         if (!escaped_url)
55                 return -ENOMEM;
56
57         d = opendir(image_root);
58         if (!d) {
59                 if (errno == ENOENT) {
60                         *etags = NULL;
61                         return 0;
62                 }
63
64                 return -errno;
65         }
66
67         FOREACH_DIRENT_ALL(de, d, return -errno) {
68                 const char *a, *b;
69                 char *u;
70
71                 if (de->d_type != DT_UNKNOWN &&
72                     de->d_type != dt)
73                         continue;
74
75                 if (prefix) {
76                         a = startswith(de->d_name, prefix);
77                         if (!a)
78                                 continue;
79                 } else
80                         a = de->d_name;
81
82                 a = startswith(a, escaped_url);
83                 if (!a)
84                         continue;
85
86                 a = startswith(a, ".");
87                 if (!a)
88                         continue;
89
90                 if (suffix) {
91                         b = endswith(de->d_name, suffix);
92                         if (!b)
93                                 continue;
94                 } else
95                         b = strchr(de->d_name, 0);
96
97                 if (a >= b)
98                         continue;
99
100                 u = cunescape_length(a, b - a);
101                 if (!u)
102                         return -ENOMEM;
103
104                 if (!http_etag_is_valid(u)) {
105                         free(u);
106                         continue;
107                 }
108
109                 r = strv_consume(&l, u);
110                 if (r < 0)
111                         return r;
112         }
113
114         *etags = l;
115         l = NULL;
116
117         return 0;
118 }
119
120 int import_make_local_copy(const char *final, const char *image_root, const char *local, bool force_local) {
121         const char *p;
122         int r;
123
124         assert(final);
125         assert(local);
126
127         if (!image_root)
128                 image_root = "/var/lib/machines";
129
130         p = strappenda(image_root, "/", local);
131
132         if (force_local) {
133                 (void) btrfs_subvol_remove(p);
134                 (void) rm_rf_dangerous(p, false, true, false);
135         }
136
137         r = btrfs_subvol_snapshot(final, p, false, false);
138         if (r == -ENOTTY) {
139                 r = copy_tree(final, p, false);
140                 if (r < 0)
141                         return log_error_errno(r, "Failed to copy image: %m");
142         } else if (r < 0)
143                 return log_error_errno(r, "Failed to create local image: %m");
144
145         log_info("Created new local image '%s'.", local);
146
147         return 0;
148 }
149
150 int import_make_read_only(const char *path) {
151         int r;
152
153         r = btrfs_subvol_set_read_only(path, true);
154         if (r == -ENOTTY) {
155                 struct stat st;
156
157                 r = stat(path, &st);
158                 if (r < 0)
159                         return log_error_errno(errno, "Failed to stat temporary image: %m");
160
161                 if (chmod(path, st.st_mode & 0755) < 0)
162                         return log_error_errno(errno, "Failed to chmod() final image: %m");
163
164                 return 0;
165         }
166         if (r < 0)
167                 return log_error_errno(r, "Failed to mark final image read-only: %m");
168
169         return 0;
170 }
171
172 int import_make_path(const char *url, const char *etag, const char *image_root, const char *prefix, const char *suffix, char **ret) {
173         _cleanup_free_ char *escaped_url = NULL;
174         char *path;
175
176         assert(url);
177         assert(ret);
178
179         if (!image_root)
180                 image_root = "/var/lib/machines";
181
182         escaped_url = xescape(url, FILENAME_ESCAPE);
183         if (!escaped_url)
184                 return -ENOMEM;
185
186         if (etag) {
187                 _cleanup_free_ char *escaped_etag = NULL;
188
189                 escaped_etag = xescape(etag, FILENAME_ESCAPE);
190                 if (!escaped_etag)
191                         return -ENOMEM;
192
193                 path = strjoin(image_root, "/", strempty(prefix), escaped_url, ".", escaped_etag, strempty(suffix), NULL);
194         } else
195                 path = strjoin(image_root, "/", strempty(prefix), escaped_url, strempty(suffix), NULL);
196         if (!path)
197                 return -ENOMEM;
198
199         *ret = path;
200         return 0;
201 }