1 /*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
4 This file is part of systemd.
6 Copyright 2015 Lennart Poettering
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.
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.
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/>.
25 #include "btrfs-util.h"
26 #include "import-util.h"
28 #define FILENAME_ESCAPE "/.#\"\'"
30 bool http_etag_is_valid(const char *etag) {
31 if (!endswith(etag, "\""))
34 if (!startswith(etag, "\"") && !startswith(etag, "W/\""))
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;
51 image_root = "/var/lib/machines";
53 escaped_url = xescape(url, FILENAME_ESCAPE);
57 d = opendir(image_root);
59 if (errno == ENOENT) {
67 FOREACH_DIRENT_ALL(de, d, return -errno) {
71 if (de->d_type != DT_UNKNOWN &&
76 a = startswith(de->d_name, prefix);
82 a = startswith(a, escaped_url);
86 a = startswith(a, ".");
91 b = endswith(de->d_name, suffix);
95 b = strchr(de->d_name, 0);
100 u = cunescape_length(a, b - a);
104 if (!http_etag_is_valid(u)) {
109 r = strv_consume(&l, u);
120 int import_make_local_copy(const char *final, const char *image_root, const char *local, bool force_local) {
128 image_root = "/var/lib/machines";
130 p = strappenda(image_root, "/", local);
133 (void) btrfs_subvol_remove(p);
134 (void) rm_rf_dangerous(p, false, true, false);
137 r = btrfs_subvol_snapshot(final, p, false, false);
139 r = copy_tree(final, p, false);
141 return log_error_errno(r, "Failed to copy image: %m");
143 return log_error_errno(r, "Failed to create local image: %m");
145 log_info("Created new local image '%s'.", local);
150 int import_make_read_only_fd(int fd) {
155 /* First, let's make this a read-only subvolume if it refers
157 r = btrfs_subvol_set_read_only_fd(fd, true);
158 if (r == -ENOTTY || r == -ENOTDIR || r == -EINVAL) {
161 /* This doesn't refer to a subvolume, or the file
162 * system isn't even btrfs. In that, case fall back to
167 return log_error_errno(errno, "Failed to stat temporary image: %m");
170 if (fchmod(fd, st.st_mode & 07555) < 0)
171 return log_error_errno(errno, "Failed to chmod() final image: %m");
176 return log_error_errno(r, "Failed to make subvolume read-only: %m");
181 int import_make_read_only(const char *path) {
182 _cleanup_close_ int fd = 1;
184 fd = open(path, O_RDONLY|O_NOCTTY|O_CLOEXEC);
186 return log_error_errno(errno, "Failed to open %s: %m", path);
188 return import_make_read_only_fd(fd);
191 int import_make_path(const char *url, const char *etag, const char *image_root, const char *prefix, const char *suffix, char **ret) {
192 _cleanup_free_ char *escaped_url = NULL;
199 image_root = "/var/lib/machines";
201 escaped_url = xescape(url, FILENAME_ESCAPE);
206 _cleanup_free_ char *escaped_etag = NULL;
208 escaped_etag = xescape(etag, FILENAME_ESCAPE);
212 path = strjoin(image_root, "/", strempty(prefix), escaped_url, ".", escaped_etag, strempty(suffix), NULL);
214 path = strjoin(image_root, "/", strempty(prefix), escaped_url, strempty(suffix), NULL);
222 int import_url_last_component(const char *url, char **ret) {
226 e = strchrnul(url, '?');
228 while (e > url && e[-1] == '/')
232 while (p > url && p[-1] != '/')
238 s = strndup(p, e - p);
247 int import_url_change_last_component(const char *url, const char *suffix, char **ret) {
254 e = strchrnul(url, '?');
256 while (e > url && e[-1] == '/')
259 while (e > url && e[-1] != '/')
265 s = new(char, (e - url) + strlen(suffix) + 1);
269 strcpy(mempcpy(s, url, e - url), suffix);
274 static const char* const import_verify_table[_IMPORT_VERIFY_MAX] = {
275 [IMPORT_VERIFY_NO] = "no",
276 [IMPORT_VERIFY_SUM] = "sum",
277 [IMPORT_VERIFY_SIGNATURE] = "signature",
280 DEFINE_STRING_TABLE_LOOKUP(import_verify, ImportVerify);