uint64_t start, end, total;
struct fdisk_context *fdisk_context;
+ int fdisk_context_fd;
uint64_t sector_size, grain_size, default_fs_sector_size;
sd_id128_t seed;
.empty = empty,
.dry_run = dry_run,
.backing_fd = -EBADF,
+ .fdisk_context_fd = -EBADF,
};
return context;
if (context->fdisk_context)
sym_fdisk_unref_context(context->fdisk_context);
+ safe_close(context->fdisk_context_fd);
safe_close(context->backing_fd);
if (context->node_is_our_file)
return 0;
}
-static int context_open_and_lock_backing_fd(const char *node, int operation, int *backing_fd) {
+static int context_open_and_lock_backing_fd(const char *node, int operation, int mode, int *backing_fd) {
_cleanup_close_ int fd = -EBADF;
assert(node);
assert(backing_fd);
+ assert(IN_SET(mode, O_RDONLY, O_RDWR));
if (*backing_fd >= 0)
return 0;
- fd = open(node, O_RDONLY|O_CLOEXEC);
+ fd = open(node, mode|O_CLOEXEC);
if (fd < 0)
return log_error_errno(errno, "Failed to open device '%s': %m", node);
assert(src);
- r = context_open_and_lock_backing_fd(src, LOCK_SH, &fd);
+ r = context_open_and_lock_backing_fd(src, LOCK_SH, O_RDONLY, &fd);
if (r < 0)
return r;
return 1; /* Starting from scratch */
}
+static int context_open_mode(Context *context) {
+ return ASSERT_PTR(context)->dry_run ? O_RDONLY : O_RDWR;
+}
+
static int context_load_partition_table(Context *context) {
+ _cleanup_close_ int fd = -EBADF;
_cleanup_(fdisk_unref_contextp) struct fdisk_context *c = NULL;
_cleanup_(fdisk_unref_tablep) struct fdisk_table *t = NULL;
uint64_t left_boundary = UINT64_MAX, first_lba, last_lba, nsectors;
assert(context);
assert(context->node);
assert(!context->fdisk_context);
+ assert(context->fdisk_context_fd < 0);
assert(!context->free_areas);
assert(context->start == UINT64_MAX);
assert(context->end == UINT64_MAX);
r = context_open_and_lock_backing_fd(
context->node,
context->dry_run ? LOCK_SH : LOCK_EX,
+ context_open_mode(context),
&context->backing_fd);
if (r < 0)
return r;
if (r < 0)
return log_error_errno(r, "Failed to set sector size: %m");
- /* libfdisk doesn't have an API to operate on arbitrary fds, hence reopen the fd going via the
- * /proc/self/fd/ magic path if we have an existing fd. Open the original file otherwise. */
- r = sym_fdisk_assign_device(
+ if (context->backing_fd < 0) {
+ fd = open(context->node, context_open_mode(context)|O_CLOEXEC);
+ if (fd < 0)
+ return log_error_errno(errno, "Failed to open backing node '%s': %m", context->node);
+ }
+ r = sym_fdisk_assign_device_by_fd(
c,
- context->backing_fd >= 0 ? FORMAT_PROC_FD_PATH(context->backing_fd) : context->node,
+ context->backing_fd >= 0 ? context->backing_fd : fd,
+ context->node,
context->dry_run);
if (r == -EINVAL && arg_size_auto) {
struct stat st;
* it if automatic sizing is requested. */
if (context->backing_fd < 0)
- r = stat(context->node, &st);
+ r = fstat(fd, &st);
else
r = fstat(context->backing_fd, &st);
if (r < 0)
/* If we have no fd referencing the device yet, make a copy of the fd now, so that we have one */
r = context_open_and_lock_backing_fd(FORMAT_PROC_FD_PATH(sym_fdisk_get_devfd(c)),
context->dry_run ? LOCK_SH : LOCK_EX,
+ context_open_mode(context),
&context->backing_fd);
if (r < 0)
return r;
context->default_fs_sector_size = fs_secsz;
context->grain_size = grainsz;
context->fdisk_context = TAKE_PTR(c);
+ context->fdisk_context_fd = TAKE_FD(fd);
return from_scratch;
}
sym_fdisk_unref_context(context->fdisk_context);
context->fdisk_context = NULL;
}
+ context->fdisk_context_fd = safe_close(context->fdisk_context_fd);
context_free_free_areas(context);
}
assert(ret);
assert(ret_fd);
- fd = chase_and_open(p, root, CHASE_PREFIX_ROOT, mode, &found_path);
+ fd = chase_and_open(p, root, CHASE_PREFIX_ROOT, (mode & ~O_ACCMODE_STRICT) | O_RDONLY, &found_path);
if (fd < 0)
return fd;
if (fstat(fd, &st) < 0)
return -errno;
+ if ((S_ISREG(st.st_mode) || S_ISBLK(st.st_mode)) && (mode & O_ACCMODE_STRICT) != O_RDONLY) {
+ _cleanup_close_ int new_fd = fd_reopen(fd, mode);
+ if (new_fd < 0)
+ return new_fd;
+
+ close_and_replace(fd, new_fd);
+ }
+
if (S_ISREG(st.st_mode)) {
*ret = TAKE_PTR(found_path);
*ret_fd = TAKE_FD(fd);
static int find_root(Context *context) {
_cleanup_free_ char *device = NULL;
- int r;
+ int r, open_flags = O_CLOEXEC|context_open_mode(context);
assert(context);
if (!s)
return log_oom();
- fd = xopenat_full(AT_FDCWD, arg_node, O_RDONLY|O_CREAT|O_EXCL|O_CLOEXEC|O_NOFOLLOW, XO_NOCOW, 0666);
+ fd = xopenat_full(AT_FDCWD, arg_node, open_flags|O_CREAT|O_EXCL|O_NOFOLLOW, XO_NOCOW, 0666);
if (fd < 0)
return log_error_errno(fd, "Failed to create '%s': %m", arg_node);
/* Note that we don't specify a root argument here: if the user explicitly configured a node
* we'll take it relative to the host, not the image */
- r = acquire_root_devno(arg_node, NULL, O_RDONLY|O_CLOEXEC, &context->node, &context->backing_fd);
+ r = acquire_root_devno(arg_node, NULL, open_flags, &context->node, &context->backing_fd);
if (r == -EUCLEAN)
return btrfs_log_dev_root(LOG_ERR, r, arg_node);
if (r < 0)
FOREACH_STRING(p, "/", "/usr") {
- r = acquire_root_devno(p, arg_root, O_RDONLY|O_DIRECTORY|O_CLOEXEC, &context->node,
+ r = acquire_root_devno(p, arg_root, open_flags|O_DIRECTORY, &context->node,
&context->backing_fd);
if (r < 0) {
if (r == -EUCLEAN)
} else if (r < 0)
return log_error_errno(r, "Failed to read symlink /run/systemd/volatile-root: %m");
else {
- r = acquire_root_devno(device, NULL, O_RDONLY|O_CLOEXEC, &context->node, &context->backing_fd);
+ r = acquire_root_devno(device, NULL, open_flags, &context->node, &context->backing_fd);
if (r == -EUCLEAN)
return btrfs_log_dev_root(LOG_ERR, r, device);
if (r < 0)