sd_bus_error *error) {
Image *image = userdata;
- Manager *m = image->userdata;
+ Manager *m = ASSERT_PTR(image->userdata);
int read_only, r;
assert(message);
return 1; /* Will call us back */
}
- r = image_read_only(image, read_only);
+ r = image_read_only(image, read_only, m->runtime_scope);
if (r < 0)
return r;
void *userdata,
sd_bus_error *error) {
- Image *image = userdata;
+ Image *image = ASSERT_PTR(userdata);
+ Manager *m = ASSERT_PTR(image->userdata);
int r;
if (!image->metadata_valid) {
- r = image_read_metadata(image, &image_policy_container);
+ r = image_read_metadata(image, &image_policy_container, m->runtime_scope);
if (r < 0)
return sd_bus_error_set_errnof(error, r, "Failed to read image metadata: %m");
}
sd_bus_error *error) {
_cleanup_(sd_bus_message_unrefp) sd_bus_message *reply = NULL;
- Image *image = userdata;
+ Image *image = ASSERT_PTR(userdata);
+ Manager *m = ASSERT_PTR(image->userdata);
int r;
if (!image->metadata_valid) {
- r = image_read_metadata(image, &image_policy_container);
+ r = image_read_metadata(image, &image_policy_container, m->runtime_scope);
if (r < 0)
return sd_bus_error_set_errnof(error, r, "Failed to read image metadata: %m");
}
void *userdata,
sd_bus_error *error) {
- Image *image = userdata;
+ Image *image = ASSERT_PTR(userdata);
+ Manager *m = ASSERT_PTR(image->userdata);
int r;
if (!image->metadata_valid) {
- r = image_read_metadata(image, &image_policy_container);
+ r = image_read_metadata(image, &image_policy_container, m->runtime_scope);
if (r < 0)
return sd_bus_error_set_errnof(error, r, "Failed to read image metadata: %m");
}
void *userdata,
sd_bus_error *error) {
- Image *image = userdata;
+ Image *image = ASSERT_PTR(userdata);
+ Manager *m = ASSERT_PTR(image->userdata);
int r;
if (!image->metadata_valid) {
- r = image_read_metadata(image, &image_policy_container);
+ r = image_read_metadata(image, &image_policy_container, m->runtime_scope);
if (r < 0)
return sd_bus_error_set_errnof(error, r, "Failed to read image metadata: %m");
}
}
if (p.read_only >= 0) {
- r = image_read_only(image, p.read_only);
+ r = image_read_only(image, p.read_only, manager->runtime_scope);
if (r < 0)
RET_GATHER(ret, log_debug_errno(r, "Failed to toggle image read only, ignoring: %m"));
}
return lookup_machine_and_call_method(link, parameters, flags, userdata, vl_method_open_root_directory_internal);
}
-static int list_image_one_and_maybe_read_metadata(sd_varlink *link, Image *image, bool more, AcquireMetadata am) {
+static int list_image_one_and_maybe_read_metadata(Manager *m, sd_varlink *link, Image *image, bool more, AcquireMetadata am) {
int r;
+ assert(m);
assert(link);
assert(image);
if (should_acquire_metadata(am) && !image->metadata_valid) {
- r = image_read_metadata(image, &image_policy_container);
+ r = image_read_metadata(image, &image_policy_container, m->runtime_scope);
if (r < 0 && am != ACQUIRE_METADATA_GRACEFUL)
return log_debug_errno(r, "Failed to read image metadata: %m");
if (r < 0)
if (r < 0)
return log_debug_errno(r, "Failed to find image: %m");
- return list_image_one_and_maybe_read_metadata(link, found, /* more = */ false, p.acquire_metadata);
+ return list_image_one_and_maybe_read_metadata(m, link, found, /* more = */ false, p.acquire_metadata);
}
if (!FLAGS_SET(flags, SD_VARLINK_METHOD_MORE))
Image *image, *previous = NULL;
HASHMAP_FOREACH(image, images) {
if (previous) {
- r = list_image_one_and_maybe_read_metadata(link, previous, /* more = */ true, p.acquire_metadata);
+ r = list_image_one_and_maybe_read_metadata(m, link, previous, /* more = */ true, p.acquire_metadata);
if (r < 0)
return r;
}
}
if (previous)
- return list_image_one_and_maybe_read_metadata(link, previous, /* more = */ false, p.acquire_metadata);
+ return list_image_one_and_maybe_read_metadata(m, link, previous, /* more = */ false, p.acquire_metadata);
return sd_varlink_error(link, VARLINK_ERROR_MACHINE_IMAGE_NO_SUCH_IMAGE, NULL);
}
/* We take an exclusive lock on this image, since it's our private, ephemeral copy
* only owned by us and no one else. */
r = image_path_lock(
+ arg_privileged ? RUNTIME_SCOPE_SYSTEM : RUNTIME_SCOPE_USER,
np,
LOCK_EX|LOCK_NB,
arg_privileged ? &tree_global_lock : NULL,
goto finish;
r = image_path_lock(
+ arg_privileged ? RUNTIME_SCOPE_SYSTEM : RUNTIME_SCOPE_USER,
arg_directory,
(arg_read_only ? LOCK_SH : LOCK_EX) | LOCK_NB,
arg_privileged ? &tree_global_lock : NULL,
/* Always take an exclusive lock on our own ephemeral copy. */
r = image_path_lock(
+ arg_privileged ? RUNTIME_SCOPE_SYSTEM : RUNTIME_SCOPE_USER,
np,
LOCK_EX|LOCK_NB,
arg_privileged ? &tree_global_lock : NULL,
remove_image = true;
} else {
r = image_path_lock(
+ arg_privileged ? RUNTIME_SCOPE_SYSTEM : RUNTIME_SCOPE_USER,
arg_image,
(arg_read_only ? LOCK_SH : LOCK_EX) | LOCK_NB,
arg_privileged ? &tree_global_lock : NULL,
return 1;
if (!image->metadata_valid) {
- r = image_read_metadata(image, &image_policy_service);
+ r = image_read_metadata(image, &image_policy_service, m->runtime_scope);
if (r < 0)
return sd_bus_error_set_errnof(error, r, "Failed to read image metadata: %m");
}
if (r == 0)
return 1; /* Will call us back */
- r = image_read_only(image, read_only);
+ r = image_read_only(image, read_only, m->runtime_scope);
if (r < 0)
return r;
#include "chase.h"
#include "chattr-util.h"
#include "copy.h"
+#include "devnum-util.h"
#include "dirent-util.h"
#include "discover-image.h"
#include "dissect-image.h"
#include "mkdir.h"
#include "nulstr-util.h"
#include "os-util.h"
+#include "path-lookup.h"
#include "path-util.h"
#include "rm-rf.h"
#include "runtime-scope.h"
return r;
/* Make sure we don't interfere with a running nspawn */
- r = image_path_lock(i->path, LOCK_EX|LOCK_NB, &global_lock, &local_lock);
+ r = image_path_lock(scope, i->path, LOCK_EX|LOCK_NB, &global_lock, &local_lock);
if (r < 0)
return r;
return r;
/* Make sure we don't interfere with a running nspawn */
- r = image_path_lock(i->path, LOCK_EX|LOCK_NB, &global_lock, &local_lock);
+ r = image_path_lock(scope, i->path, LOCK_EX|LOCK_NB, &global_lock, &local_lock);
if (r < 0)
return r;
/* Make sure nobody takes the new name, between the time we
* checked it is currently unused in all search paths, and the
* time we take possession of it */
- r = image_name_lock(new_name, LOCK_EX|LOCK_NB, &name_lock);
+ r = image_name_lock(scope, new_name, LOCK_EX|LOCK_NB, &name_lock);
if (r < 0)
return r;
/* Make sure nobody takes the new name, between the time we
* checked it is currently unused in all search paths, and the
* time we take possession of it */
- r = image_name_lock(new_name, LOCK_EX|LOCK_NB, &name_lock);
+ r = image_name_lock(scope, new_name, LOCK_EX|LOCK_NB, &name_lock);
if (r < 0)
return r;
return 0;
}
-int image_read_only(Image *i, bool b) {
+int image_read_only(Image *i, bool b, RuntimeScope scope) {
_cleanup_(release_lock_file) LockFile global_lock = LOCK_FILE_INIT, local_lock = LOCK_FILE_INIT;
int r;
return -EROFS;
/* Make sure we don't interfere with a running nspawn */
- r = image_path_lock(i->path, LOCK_EX|LOCK_NB, &global_lock, &local_lock);
+ r = image_path_lock(scope, i->path, LOCK_EX|LOCK_NB, &global_lock, &local_lock);
if (r < 0)
return r;
return 0;
}
-static void make_lock_dir(void) {
- (void) mkdir_p("/run/systemd/nspawn", 0755);
- (void) mkdir("/run/systemd/nspawn/locks", 0700);
+static int make_lock_dir(RuntimeScope scope) {
+ int r;
+
+ _cleanup_free_ char *p = NULL;
+ r = runtime_directory_generic(scope, "systemd", &p);
+ if (r < 0)
+ return r;
+
+ _cleanup_close_ int pfd = open_mkdir_at(AT_FDCWD, p, O_CLOEXEC, 0755);
+ if (pfd < 0)
+ return pfd;
+
+ _cleanup_close_ int nfd = open_mkdir_at(pfd, "nspawn", O_CLOEXEC, 0755);
+ if (nfd < 0)
+ return nfd;
+
+ r = RET_NERRNO(mkdirat(nfd, "locks", 0700));
+ if (r == -EEXIST)
+ return 0;
+ if (r < 0)
+ return r;
+
+ return 1;
}
int image_path_lock(
+ RuntimeScope scope,
const char *path,
int operation,
LockFile *ret_global,
assert(ret_local);
/* Locks an image path. This actually creates two locks: one "local" one, next to the image path
- * itself, which might be shared via NFS. And another "global" one, in /run, that uses the
+ * itself, which might be shared via NFS. And another "global" one, in /run/, that uses the
* device/inode number. This has the benefit that we can even lock a tree that is a mount point,
* correctly. */
}
if (ret_global) {
- if (stat(path, &st) >= 0) {
+ if (stat(path, &st) < 0)
+ log_debug_errno(errno, "Failed to stat() image '%s', not locking image: %m", path);
+ else {
+ r = runtime_directory_generic(scope, "systemd/nspawn/locks/", &p);
+ if (r < 0)
+ return r;
+
if (S_ISBLK(st.st_mode))
- r = asprintf(&p, "/run/systemd/nspawn/locks/block-%u:%u", major(st.st_rdev), minor(st.st_rdev));
+ r = strextendf(&p, "block-" DEVNUM_FORMAT_STR, DEVNUM_FORMAT_VAL(st.st_rdev));
else if (S_ISDIR(st.st_mode) || S_ISREG(st.st_mode))
- r = asprintf(&p, "/run/systemd/nspawn/locks/inode-%lu:%lu", (unsigned long) st.st_dev, (unsigned long) st.st_ino);
+ r = strextendf(&p, "inode-%" PRIu64 ":%" PRIu64, (uint64_t) st.st_dev, (uint64_t) st.st_ino);
else
return -ENOTTY;
if (r < 0)
- return -ENOMEM;
+ return r;
}
}
if (!path_startswith(path, "/dev/")) {
r = make_lock_file_for(path, operation, &t);
if (r < 0) {
- if (!exclusive && r == -EROFS)
- log_debug_errno(r, "Failed to create shared lock for '%s', ignoring: %m", path);
- else
+ if (exclusive || r != -EROFS)
return r;
+
+ log_debug_errno(r, "Failed to create shared lock for '%s', ignoring: %m", path);
}
}
if (p) {
- make_lock_dir();
+ (void) make_lock_dir(scope);
r = make_lock_file(p, operation, ret_global);
if (r < 0) {
return 0;
}
-int image_read_metadata(Image *i, const ImagePolicy *image_policy) {
+int image_read_metadata(Image *i, const ImagePolicy *image_policy, RuntimeScope scope) {
_cleanup_(release_lock_file) LockFile global_lock = LOCK_FILE_INIT, local_lock = LOCK_FILE_INIT;
int r;
assert(i);
- r = image_path_lock(i->path, LOCK_SH|LOCK_NB, &global_lock, &local_lock);
+ r = image_path_lock(scope, i->path, LOCK_SH|LOCK_NB, &global_lock, &local_lock);
if (r < 0)
return r;
return 0;
}
-int image_name_lock(const char *name, int operation, LockFile *ret) {
- const char *p;
+int image_name_lock(
+ RuntimeScope scope,
+ const char *name,
+ int operation,
+ LockFile *ret) {
+
+ int r;
assert(name);
assert(ret);
return 0;
}
- make_lock_dir();
+ (void) make_lock_dir(scope);
+
+ _cleanup_free_ char *p = NULL;
+ r = runtime_directory_generic(scope, "systemd/nspawn/locks/name-", &p);
+ if (r < 0)
+ return r;
+
+ if (!strextend(&p, name))
+ return -ENOMEM;
- p = strjoina("/run/systemd/nspawn/locks/name-", name);
return make_lock_file(p, operation, ret);
}
int image_remove(Image *i, RuntimeScope scope);
int image_rename(Image *i, const char *new_name, RuntimeScope scope);
int image_clone(Image *i, const char *new_name, bool read_only, RuntimeScope scope);
-int image_read_only(Image *i, bool b);
+int image_read_only(Image *i, bool b, RuntimeScope scope);
const char* image_type_to_string(ImageType t) _const_;
ImageType image_type_from_string(const char *s) _pure_;
-int image_path_lock(const char *path, int operation, LockFile *global, LockFile *local);
-int image_name_lock(const char *name, int operation, LockFile *ret);
+int image_path_lock(RuntimeScope scope, const char *path, int operation, LockFile *global, LockFile *local);
+int image_name_lock(RuntimeScope scope, const char *name, int operation, LockFile *ret);
int image_set_limit(Image *i, uint64_t referenced_max);
int image_set_pool_limit(RuntimeScope scope, ImageClass class, uint64_t referenced_max);
-int image_read_metadata(Image *i, const ImagePolicy *image_policy);
+int image_read_metadata(Image *i, const ImagePolicy *image_policy, RuntimeScope scope);
bool image_in_search_path(RuntimeScope scope, ImageClass class, const char *root, const char *image);
return log_error_errno(r, "Failed to discover images: %m");
HASHMAP_FOREACH(img, images) {
- r = image_read_metadata(img, image_class_info[image_class].default_image_policy);
+ r = image_read_metadata(img, image_class_info[image_class].default_image_policy, RUNTIME_SCOPE_SYSTEM);
if (r < 0)
return log_error_errno(r, "Failed to read metadata for image %s: %m", img->name);
}