mirror of
https://github.com/systemd/systemd-stable.git
synced 2024-12-23 17:34:00 +03:00
machinectl/machined: implement "rename", "clone", "read-only" verbs for machine images
This commit is contained in:
parent
086821244b
commit
ebd93cb684
@ -310,7 +310,7 @@ LIBS="$save_LIBS"
|
||||
|
||||
AC_CHECK_FUNCS([memfd_create])
|
||||
AC_CHECK_FUNCS([__secure_getenv secure_getenv])
|
||||
AC_CHECK_DECLS([gettid, pivot_root, name_to_handle_at, setns, getrandom, LO_FLAGS_PARTSCAN],
|
||||
AC_CHECK_DECLS([gettid, pivot_root, name_to_handle_at, setns, getrandom, renameat2, LO_FLAGS_PARTSCAN],
|
||||
[], [], [[
|
||||
#include <sys/types.h>
|
||||
#include <unistd.h>
|
||||
|
@ -236,6 +236,95 @@ static int method_remove(
|
||||
return sd_bus_reply_method_return(message, NULL);
|
||||
}
|
||||
|
||||
static int method_rename(
|
||||
sd_bus *bus,
|
||||
sd_bus_message *message,
|
||||
void *userdata,
|
||||
sd_bus_error *error) {
|
||||
|
||||
_cleanup_(image_unrefp) Image *image = NULL;
|
||||
const char *new_name;
|
||||
int r;
|
||||
|
||||
assert(bus);
|
||||
assert(message);
|
||||
|
||||
r = image_find_by_bus_path_with_error(sd_bus_message_get_path(message), &image, error);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
r = sd_bus_message_read(message, "s", &new_name);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
if (!image_name_is_valid(new_name))
|
||||
return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Image name '%s' is invalid.", new_name);
|
||||
|
||||
r = image_rename(image, new_name);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
return sd_bus_reply_method_return(message, NULL);
|
||||
}
|
||||
|
||||
static int method_clone(
|
||||
sd_bus *bus,
|
||||
sd_bus_message *message,
|
||||
void *userdata,
|
||||
sd_bus_error *error) {
|
||||
|
||||
_cleanup_(image_unrefp) Image *image = NULL;
|
||||
const char *new_name;
|
||||
int r, read_only;
|
||||
|
||||
assert(bus);
|
||||
assert(message);
|
||||
|
||||
r = image_find_by_bus_path_with_error(sd_bus_message_get_path(message), &image, error);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
r = sd_bus_message_read(message, "sb", &new_name, &read_only);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
if (!image_name_is_valid(new_name))
|
||||
return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Image name '%s' is invalid.", new_name);
|
||||
|
||||
r = image_clone(image, new_name, read_only);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
return sd_bus_reply_method_return(message, NULL);
|
||||
}
|
||||
|
||||
static int method_mark_read_only(
|
||||
sd_bus *bus,
|
||||
sd_bus_message *message,
|
||||
void *userdata,
|
||||
sd_bus_error *error) {
|
||||
|
||||
_cleanup_(image_unrefp) Image *image = NULL;
|
||||
int r, read_only;
|
||||
|
||||
assert(bus);
|
||||
assert(message);
|
||||
|
||||
r = image_find_by_bus_path_with_error(sd_bus_message_get_path(message), &image, error);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
r = sd_bus_message_read(message, "b", &read_only);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
r = image_read_only(image, read_only);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
return sd_bus_reply_method_return(message, NULL);
|
||||
}
|
||||
|
||||
const sd_bus_vtable image_vtable[] = {
|
||||
SD_BUS_VTABLE_START(0),
|
||||
SD_BUS_PROPERTY("Name", "s", property_get_name, 0, 0),
|
||||
@ -245,6 +334,9 @@ const sd_bus_vtable image_vtable[] = {
|
||||
SD_BUS_PROPERTY("CreationTimestamp", "t", property_get_crtime, 0, 0),
|
||||
SD_BUS_PROPERTY("ModificationTimestamp", "t", property_get_mtime, 0, 0),
|
||||
SD_BUS_METHOD("Remove", NULL, NULL, method_remove, 0),
|
||||
SD_BUS_METHOD("Rename", "s", NULL, method_rename, 0),
|
||||
SD_BUS_METHOD("Clone", "sb", NULL, method_clone, 0),
|
||||
SD_BUS_METHOD("MarkeReadOnly", "b", NULL, method_mark_read_only, 0),
|
||||
SD_BUS_VTABLE_END
|
||||
};
|
||||
|
||||
|
@ -1286,13 +1286,11 @@ static int login_machine(int argc, char *argv[], void *userdata) {
|
||||
static int remove_image(int argc, char *argv[], void *userdata) {
|
||||
_cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
|
||||
sd_bus *bus = userdata;
|
||||
int i;
|
||||
int r, i;
|
||||
|
||||
assert(bus);
|
||||
|
||||
for (i = 1; i < argc; i++) {
|
||||
int r;
|
||||
|
||||
r = sd_bus_call_method(
|
||||
bus,
|
||||
"org.freedesktop.machine1",
|
||||
@ -1311,6 +1309,80 @@ static int remove_image(int argc, char *argv[], void *userdata) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int rename_image(int argc, char *argv[], void *userdata) {
|
||||
_cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
|
||||
sd_bus *bus = userdata;
|
||||
int r;
|
||||
|
||||
r = sd_bus_call_method(
|
||||
bus,
|
||||
"org.freedesktop.machine1",
|
||||
"/org/freedesktop/machine1",
|
||||
"org.freedesktop.machine1.Manager",
|
||||
"RenameImage",
|
||||
&error,
|
||||
NULL,
|
||||
"ss", argv[1], argv[2]);
|
||||
if (r < 0) {
|
||||
log_error("Could not rename image: %s", bus_error_message(&error, -r));
|
||||
return r;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int clone_image(int argc, char *argv[], void *userdata) {
|
||||
_cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
|
||||
sd_bus *bus = userdata;
|
||||
int r;
|
||||
|
||||
r = sd_bus_call_method(
|
||||
bus,
|
||||
"org.freedesktop.machine1",
|
||||
"/org/freedesktop/machine1",
|
||||
"org.freedesktop.machine1.Manager",
|
||||
"CloneImage",
|
||||
&error,
|
||||
NULL,
|
||||
"ssb", argv[1], argv[2], arg_read_only);
|
||||
if (r < 0) {
|
||||
log_error("Could not clone image: %s", bus_error_message(&error, -r));
|
||||
return r;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int read_only_image(int argc, char *argv[], void *userdata) {
|
||||
_cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
|
||||
sd_bus *bus = userdata;
|
||||
int b = true, r;
|
||||
|
||||
if (argc > 2) {
|
||||
b = parse_boolean(argv[2]);
|
||||
if (b < 0) {
|
||||
log_error("Failed to parse boolean argument: %s", argv[2]);
|
||||
return -EINVAL;
|
||||
}
|
||||
}
|
||||
|
||||
r = sd_bus_call_method(
|
||||
bus,
|
||||
"org.freedesktop.machine1",
|
||||
"/org/freedesktop/machine1",
|
||||
"org.freedesktop.machine1.Manager",
|
||||
"MarkImageReadOnly",
|
||||
&error,
|
||||
NULL,
|
||||
"sb", argv[1], b);
|
||||
if (r < 0) {
|
||||
log_error("Could not mark image read-only: %s", bus_error_message(&error, -r));
|
||||
return r;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int help(int argc, char *argv[], void *userdata) {
|
||||
|
||||
printf("%s [OPTIONS...] {COMMAND} ...\n\n"
|
||||
@ -1336,15 +1408,18 @@ static int help(int argc, char *argv[], void *userdata) {
|
||||
" login NAME Get a login prompt on a container\n"
|
||||
" poweroff NAME... Power off one or more containers\n"
|
||||
" reboot NAME... Reboot one or more containers\n"
|
||||
" kill NAME... Send signal to processes of a VM/container\n"
|
||||
" terminate NAME... Terminate one or more VMs/containers\n"
|
||||
" bind NAME PATH [PATH] Bind mount a path from the host into a container\n"
|
||||
" kill NAME... Send signal to processes of a VM/container\n"
|
||||
" copy-to NAME PATH [PATH] Copy files from the host to a container\n"
|
||||
" copy-from NAME PATH [PATH] Copy files from a container to the host\n\n"
|
||||
" copy-from NAME PATH [PATH] Copy files from a container to the host\n"
|
||||
" bind NAME PATH [PATH] Bind mount a path from the host into a container\n\n"
|
||||
"Image Commands:\n"
|
||||
" list-images Show available images\n"
|
||||
" image-status NAME... Show image details\n"
|
||||
" show-image NAME... Show properties of image\n"
|
||||
" clone NAME NAME Clone an image\n"
|
||||
" rename NAME NAME Rename an image\n"
|
||||
" read-only NAME [BOOL] Mark or unmark image read-only\n"
|
||||
" remove NAME... Remove an image\n",
|
||||
program_invocation_short_name);
|
||||
|
||||
@ -1482,6 +1557,9 @@ static int machinectl_main(int argc, char *argv[], sd_bus *bus) {
|
||||
{ "copy-to", 3, 4, 0, copy_files },
|
||||
{ "copy-from", 3, 4, 0, copy_files },
|
||||
{ "remove", 2, VERB_ANY, 0, remove_image },
|
||||
{ "rename", 3, 3, 0, rename_image },
|
||||
{ "clone", 3, 3, 0, clone_image },
|
||||
{ "read-only", 2, 3, 0, read_only_image },
|
||||
{}
|
||||
};
|
||||
|
||||
|
@ -588,6 +588,90 @@ static int method_remove_image(sd_bus *bus, sd_bus_message *message, void *userd
|
||||
return sd_bus_reply_method_return(message, NULL);
|
||||
}
|
||||
|
||||
static int method_rename_image(sd_bus *bus, sd_bus_message *message, void *userdata, sd_bus_error *error) {
|
||||
_cleanup_(image_unrefp) Image* i = NULL;
|
||||
const char *old_name, *new_name;
|
||||
int r;
|
||||
|
||||
assert(bus);
|
||||
assert(message);
|
||||
|
||||
r = sd_bus_message_read(message, "ss", &old_name, &new_name);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
if (!image_name_is_valid(old_name))
|
||||
return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Image name '%s' is invalid.", old_name);
|
||||
if (!image_name_is_valid(new_name))
|
||||
return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Image name '%s' is invalid.", new_name);
|
||||
|
||||
r = image_find(old_name, &i);
|
||||
if (r < 0)
|
||||
return r;
|
||||
if (r == 0)
|
||||
return sd_bus_error_setf(error, BUS_ERROR_NO_SUCH_IMAGE, "No image '%s' known", old_name);
|
||||
|
||||
r = image_rename(i, new_name);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
return sd_bus_reply_method_return(message, NULL);
|
||||
}
|
||||
|
||||
static int method_clone_image(sd_bus *bus, sd_bus_message *message, void *userdata, sd_bus_error *error) {
|
||||
_cleanup_(image_unrefp) Image *i = NULL;
|
||||
const char *old_name, *new_name;
|
||||
int read_only, r;
|
||||
|
||||
assert(bus);
|
||||
r = sd_bus_message_read(message, "ssb", &old_name, &new_name, &read_only);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
if (!image_name_is_valid(old_name))
|
||||
return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Image name '%s' is invalid.", old_name);
|
||||
if (!image_name_is_valid(new_name))
|
||||
return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Image name '%s' is invalid.", new_name);
|
||||
|
||||
r = image_find(old_name, &i);
|
||||
if (r < 0)
|
||||
return r;
|
||||
if (r == 0)
|
||||
return sd_bus_error_setf(error, BUS_ERROR_NO_SUCH_IMAGE, "No image '%s' known", old_name);
|
||||
|
||||
r = image_clone(i, new_name, read_only);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
return sd_bus_reply_method_return(message, NULL);
|
||||
}
|
||||
|
||||
static int method_mark_image_read_only(sd_bus *bus, sd_bus_message *message, void *userdata, sd_bus_error *error) {
|
||||
_cleanup_(image_unrefp) Image *i = NULL;
|
||||
const char *name;
|
||||
int read_only, r;
|
||||
|
||||
assert(bus);
|
||||
r = sd_bus_message_read(message, "sb", &name, &read_only);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
if (!image_name_is_valid(name))
|
||||
return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Image name '%s' is invalid.", name);
|
||||
|
||||
r = image_find(name, &i);
|
||||
if (r < 0)
|
||||
return r;
|
||||
if (r == 0)
|
||||
return sd_bus_error_setf(error, BUS_ERROR_NO_SUCH_IMAGE, "No image '%s' known", name);
|
||||
|
||||
r = image_read_only(i, read_only);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
return sd_bus_reply_method_return(message, NULL);
|
||||
}
|
||||
|
||||
const sd_bus_vtable manager_vtable[] = {
|
||||
SD_BUS_VTABLE_START(0),
|
||||
SD_BUS_METHOD("GetMachine", "s", "o", method_get_machine, SD_BUS_VTABLE_UNPRIVILEGED),
|
||||
@ -606,6 +690,9 @@ const sd_bus_vtable manager_vtable[] = {
|
||||
SD_BUS_METHOD("OpenMachinePTY", "s", "hs", method_open_machine_pty, 0),
|
||||
SD_BUS_METHOD("OpenMachineLogin", "s", "hs", method_open_machine_login, SD_BUS_VTABLE_UNPRIVILEGED),
|
||||
SD_BUS_METHOD("RemoveImage", "s", NULL, method_remove_image, 0),
|
||||
SD_BUS_METHOD("RenameImage", "ss", NULL, method_rename_image, 0),
|
||||
SD_BUS_METHOD("CloneImage", "ssb", NULL, method_clone_image, 0),
|
||||
SD_BUS_METHOD("MarkImageReadOnly", "sb", NULL, method_mark_image_read_only, 0),
|
||||
SD_BUS_SIGNAL("MachineNew", "so", 0),
|
||||
SD_BUS_SIGNAL("MachineRemoved", "so", 0),
|
||||
SD_BUS_VTABLE_END
|
||||
|
@ -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;
|
||||
|
@ -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);
|
||||
|
@ -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] = {
|
||||
|
@ -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_;
|
||||
|
@ -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
|
||||
|
@ -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) {
|
||||
|
Loading…
Reference in New Issue
Block a user