summaryrefslogtreecommitdiff
path: root/src/shared
diff options
context:
space:
mode:
authorLennart Poettering <lennart@poettering.net>2014-12-27 17:44:04 +0100
committerLennart Poettering <lennart@poettering.net>2014-12-28 02:08:40 +0100
commitebd93cb684806ac0f352139e69ac8f53eb49f5e4 (patch)
tree537df721db4f8a9a05ff8a3093481f5ea5571a92 /src/shared
parent086821244b5113f00a0ef993b78dc56aae2a8f6c (diff)
machinectl/machined: implement "rename", "clone", "read-only" verbs for machine images
Diffstat (limited to 'src/shared')
-rw-r--r--src/shared/copy.c46
-rw-r--r--src/shared/copy.h1
-rw-r--r--src/shared/machine-image.c150
-rw-r--r--src/shared/machine-image.h3
-rw-r--r--src/shared/missing.h10
-rw-r--r--src/shared/util.c14
6 files changed, 207 insertions, 17 deletions
diff --git a/src/shared/copy.c b/src/shared/copy.c
index 92f6e1e114..3df636704c 100644
--- a/src/shared/copy.c
+++ b/src/shared/copy.c
@@ -120,6 +120,7 @@ static int fd_copy_symlink(int df, const char *from, const struct stat *st, int
static int fd_copy_regular(int df, const char *from, const struct stat *st, int dt, const char *to) {
_cleanup_close_ int fdf = -1, fdt = -1;
+ struct timespec ts[2];
int r, q;
assert(from);
@@ -146,7 +147,10 @@ static int fd_copy_regular(int df, const char *from, const struct stat *st, int
if (fchmod(fdt, st->st_mode & 07777) < 0)
r = -errno;
- (void) copy_times(fdf, fdt);
+ ts[0] = st->st_atim;
+ ts[1] = st->st_mtim;
+ (void) futimens(fdt, ts);
+
(void) copy_xattr(fdf, fdt);
q = close(fdt);
@@ -243,14 +247,19 @@ static int fd_copy_directory(
r = 0;
if (created) {
+ struct timespec ut[2] = {
+ st->st_atim,
+ st->st_mtim
+ };
+
if (fchown(fdt, st->st_uid, st->st_gid) < 0)
r = -errno;
if (fchmod(fdt, st->st_mode & 07777) < 0)
r = -errno;
- (void) copy_times(fdf, fdt);
- (void) copy_xattr(fdf, fdt);
+ (void) futimens(fdt, ut);
+ (void) copy_xattr(dirfd(d), fdt);
}
FOREACH_DIRENT(de, d, return -errno) {
@@ -356,9 +365,11 @@ int copy_file(const char *from, const char *to, int flags, mode_t mode) {
assert(from);
assert(to);
- fdt = open(to, flags|O_WRONLY|O_CREAT|O_CLOEXEC|O_NOCTTY, mode);
- if (fdt < 0)
- return -errno;
+ RUN_WITH_UMASK(0000) {
+ fdt = open(to, flags|O_WRONLY|O_CREAT|O_CLOEXEC|O_NOCTTY, mode);
+ if (fdt < 0)
+ return -errno;
+ }
r = copy_file_fd(from, fdt, true);
if (r < 0) {
@@ -375,6 +386,29 @@ int copy_file(const char *from, const char *to, int flags, mode_t mode) {
return 0;
}
+int copy_file_atomic(const char *from, const char *to, mode_t mode, bool replace) {
+ _cleanup_free_ char *t;
+ int r;
+
+ assert(from);
+ assert(to);
+
+ r = tempfn_random(to, &t);
+ if (r < 0)
+ return r;
+
+ r = copy_file(from, t, O_NOFOLLOW|O_EXCL, mode);
+ if (r < 0)
+ return r;
+
+ if (renameat2(AT_FDCWD, t, AT_FDCWD, to, replace ? 0 : RENAME_NOREPLACE) < 0) {
+ unlink_noerrno(t);
+ return -errno;
+ }
+
+ return 0;
+}
+
int copy_times(int fdf, int fdt) {
struct timespec ut[2];
struct stat st;
diff --git a/src/shared/copy.h b/src/shared/copy.h
index 6d725ef26d..58159a02cc 100644
--- a/src/shared/copy.h
+++ b/src/shared/copy.h
@@ -26,6 +26,7 @@
int copy_file_fd(const char *from, int to, bool try_reflink);
int copy_file(const char *from, const char *to, int flags, mode_t mode);
+int copy_file_atomic(const char *from, const char *to, mode_t mode, bool replace);
int copy_tree(const char *from, const char *to, bool merge);
int copy_tree_at(int fdf, const char *from, int fdt, const char *to, bool merge);
int copy_directory_fd(int dirfd, const char *to, bool merge);
diff --git a/src/shared/machine-image.c b/src/shared/machine-image.c
index fa06a0dc59..7c041fab76 100644
--- a/src/shared/machine-image.c
+++ b/src/shared/machine-image.c
@@ -20,11 +20,13 @@
***/
#include <sys/statfs.h>
+#include <fcntl.h>
#include "strv.h"
#include "utf8.h"
#include "btrfs-util.h"
#include "path-util.h"
+#include "copy.h"
#include "machine-image.h"
static const char image_search_path[] =
@@ -317,18 +319,158 @@ void image_hashmap_free(Hashmap *map) {
}
int image_remove(Image *i) {
- int r;
-
assert(i);
if (path_equal(i->path, "/") ||
path_startswith(i->path, "/usr"))
return -EROFS;
- if (i->type == IMAGE_SUBVOLUME)
+ switch (i->type) {
+
+ case IMAGE_SUBVOLUME:
return btrfs_subvol_remove(i->path);
- else
+
+ case IMAGE_DIRECTORY:
+ case IMAGE_GPT:
return rm_rf_dangerous(i->path, false, true, false);
+
+ default:
+ return -ENOTSUP;
+ }
+}
+
+int image_rename(Image *i, const char *new_name) {
+ _cleanup_free_ char *new_path = NULL, *nn = NULL;
+ int r;
+
+ assert(i);
+
+ if (!image_name_is_valid(new_name))
+ return -EINVAL;
+
+ if (path_equal(i->path, "/") ||
+ path_startswith(i->path, "/usr"))
+ return -EROFS;
+
+ r = image_find(new_name, NULL);
+ if (r < 0)
+ return r;
+ if (r > 0)
+ return -EEXIST;
+
+ switch (i->type) {
+
+ case IMAGE_SUBVOLUME:
+ case IMAGE_DIRECTORY:
+ new_path = file_in_same_dir(i->path, new_name);
+ break;
+
+ case IMAGE_GPT: {
+ const char *fn;
+
+ fn = strappenda(new_name, ".gpt");
+ new_path = file_in_same_dir(i->path, fn);
+ break;
+ }
+
+ default:
+ return -ENOTSUP;
+ }
+
+ if (!new_path)
+ return -ENOMEM;
+
+ nn = strdup(new_name);
+ if (!nn)
+ return -ENOMEM;
+
+ if (renameat2(AT_FDCWD, i->path, AT_FDCWD, new_path, RENAME_NOREPLACE) < 0)
+ return -errno;
+
+ free(i->path);
+ i->path = new_path;
+ new_path = NULL;
+
+ free(i->name);
+ i->name = nn;
+ nn = NULL;
+
+ return 0;
+}
+
+int image_clone(Image *i, const char *new_name, bool read_only) {
+ const char *new_path;
+ int r;
+
+ assert(i);
+
+ if (!image_name_is_valid(new_name))
+ return -EINVAL;
+
+ r = image_find(new_name, NULL);
+ if (r < 0)
+ return r;
+ if (r > 0)
+ return -EEXIST;
+
+ switch (i->type) {
+
+ case IMAGE_SUBVOLUME:
+ case IMAGE_DIRECTORY:
+ new_path = strappenda("/var/lib/container/", new_name);
+
+ r = btrfs_subvol_snapshot(i->path, new_path, read_only, true);
+ break;
+
+ case IMAGE_GPT:
+ new_path = strappenda("/var/lib/container/", new_name, ".gpt");
+
+ r = copy_file_atomic(i->path, new_path, read_only ? 0444 : 0644, false);
+ break;
+
+ default:
+ return -ENOTSUP;
+ }
+
+ if (r < 0)
+ return r;
+
+ return 0;
+}
+
+int image_read_only(Image *i, bool b) {
+ int r;
+ assert(i);
+
+ if (path_equal(i->path, "/") ||
+ path_startswith(i->path, "/usr"))
+ return -EROFS;
+
+ switch (i->type) {
+
+ case IMAGE_SUBVOLUME:
+ r = btrfs_subvol_set_read_only(i->path, b);
+ if (r < 0)
+ return r;
+ break;
+
+ case IMAGE_GPT: {
+ struct stat st;
+
+ if (stat(i->path, &st) < 0)
+ return -errno;
+
+ if (chmod(i->path, (st.st_mode & 0444) | (b ? 0000 : 0200)) < 0)
+ return -errno;
+ break;
+ }
+
+ case IMAGE_DIRECTORY:
+ default:
+ return -ENOTSUP;
+ }
+
+ return 0;
}
static const char* const image_type_table[_IMAGE_TYPE_MAX] = {
diff --git a/src/shared/machine-image.h b/src/shared/machine-image.h
index e17e32f4a5..9e0f6aedba 100644
--- a/src/shared/machine-image.h
+++ b/src/shared/machine-image.h
@@ -52,6 +52,9 @@ int image_find(const char *name, Image **ret);
int image_discover(Hashmap *map);
int image_remove(Image *i);
+int image_rename(Image *i, const char *new_name);
+int image_clone(Image *i, const char *new_name, bool read_only);
+int image_read_only(Image *i, bool b);
const char* image_type_to_string(ImageType t) _const_;
ImageType image_type_from_string(const char *s) _pure_;
diff --git a/src/shared/missing.h b/src/shared/missing.h
index dd7bef4d9d..08cf83647d 100644
--- a/src/shared/missing.h
+++ b/src/shared/missing.h
@@ -657,3 +657,13 @@ static inline int raw_clone(unsigned long flags, void *child_stack) {
static inline pid_t raw_getpid(void) {
return (pid_t) syscall(__NR_getpid);
}
+
+#if !HAVE_DECL_RENAMEAT2
+static inline int renameat2(int oldfd, const char *oldname, int newfd, const char *newname, unsigned flags) {
+ return syscall(__NR_renameat2, oldfd, oldname, newfd, newname, flags);
+}
+#endif
+
+#ifndef RENAME_NOREPLACE
+#define RENAME_NOREPLACE (1 << 0)
+#endif
diff --git a/src/shared/util.c b/src/shared/util.c
index d04d73872e..92b4d498fe 100644
--- a/src/shared/util.c
+++ b/src/shared/util.c
@@ -1152,7 +1152,7 @@ char *delete_chars(char *s, const char *bad) {
}
char *file_in_same_dir(const char *path, const char *filename) {
- char *e, *r;
+ char *e, *ret;
size_t k;
assert(path);
@@ -1165,17 +1165,17 @@ char *file_in_same_dir(const char *path, const char *filename) {
if (path_is_absolute(filename))
return strdup(filename);
- if (!(e = strrchr(path, '/')))
+ e = strrchr(path, '/');
+ if (!e)
return strdup(filename);
k = strlen(filename);
- if (!(r = new(char, e-path+1+k+1)))
+ ret = new(char, (e + 1 - path) + k + 1);
+ if (!ret)
return NULL;
- memcpy(r, path, e-path+1);
- memcpy(r+(e-path)+1, filename, k+1);
-
- return r;
+ memcpy(mempcpy(ret, path, e + 1 - path), filename, k + 1);
+ return ret;
}
int rmdir_parents(const char *path, const char *stop) {