Merge pull request #5333 from poettering/machined-copy-files-userns
machined userns fixes
This commit is contained in:
+18
-16
@@ -518,19 +518,14 @@
|
||||
<varlistentry>
|
||||
<term><command>bind</command> <replaceable>NAME</replaceable> <replaceable>PATH</replaceable> [<replaceable>PATH</replaceable>]</term>
|
||||
|
||||
<listitem><para>Bind mounts a directory from the host into the
|
||||
specified container. The first directory argument is the
|
||||
source directory on the host, the second directory argument
|
||||
is the destination directory in the container. When the
|
||||
latter is omitted, the destination path in the container is
|
||||
the same as the source path on the host. When combined with
|
||||
the <option>--read-only</option> switch, a ready-only bind
|
||||
mount is created. When combined with the
|
||||
<option>--mkdir</option> switch, the destination path is first
|
||||
created before the mount is applied. Note that this option is
|
||||
currently only supported for
|
||||
<citerefentry><refentrytitle>systemd-nspawn</refentrytitle><manvolnum>1</manvolnum></citerefentry>
|
||||
containers.</para></listitem>
|
||||
<listitem><para>Bind mounts a directory from the host into the specified container. The first directory
|
||||
argument is the source directory on the host, the second directory argument is the destination directory in the
|
||||
container. When the latter is omitted, the destination path in the container is the same as the source path on
|
||||
the host. When combined with the <option>--read-only</option> switch, a ready-only bind mount is created. When
|
||||
combined with the <option>--mkdir</option> switch, the destination path is first created before the mount is
|
||||
applied. Note that this option is currently only supported for
|
||||
<citerefentry><refentrytitle>systemd-nspawn</refentrytitle><manvolnum>1</manvolnum></citerefentry> containers,
|
||||
and only if user namespacing (<option>--private-users</option>) is not used.</para></listitem>
|
||||
</varlistentry>
|
||||
|
||||
<varlistentry>
|
||||
@@ -540,9 +535,12 @@
|
||||
system into a running container. Takes a container name,
|
||||
followed by the source path on the host and the destination
|
||||
path in the container. If the destination path is omitted, the
|
||||
same as the source path is used.</para></listitem>
|
||||
</varlistentry>
|
||||
same as the source path is used.</para>
|
||||
|
||||
<para>If host and container share the same user and group namespace, file ownership by numeric user ID and
|
||||
group ID is preserved for the copy, otherwise all files and directories in the copy will be owned by the root
|
||||
user and group (UID/GID 0).</para></listitem>
|
||||
</varlistentry>
|
||||
|
||||
<varlistentry>
|
||||
<term><command>copy-from</command> <replaceable>NAME</replaceable> <replaceable>PATH</replaceable> [<replaceable>PATH</replaceable>]</term>
|
||||
@@ -551,7 +549,11 @@
|
||||
into the host system. Takes a container name, followed by the
|
||||
source path in the container the destination path on the host.
|
||||
If the destination path is omitted, the same as the source path
|
||||
is used.</para></listitem>
|
||||
is used.</para>
|
||||
|
||||
<para>If host and container share the same user and group namespace, file ownership by numeric user ID and
|
||||
group ID is preserved for the copy, otherwise all files and directories in the copy will be owned by the root
|
||||
user and group (UID/GID 0).</para></listitem>
|
||||
</varlistentry>
|
||||
</variablelist></refsect2>
|
||||
|
||||
|
||||
@@ -474,7 +474,12 @@
|
||||
|
||||
<para>Note that the picked UID/GID range is not written to <filename>/etc/passwd</filename> or
|
||||
<filename>/etc/group</filename>. In fact, the allocation of the range is not stored persistently anywhere,
|
||||
except in the file ownership of the files and directories of the container.</para></listitem>
|
||||
except in the file ownership of the files and directories of the container.</para>
|
||||
|
||||
<para>Note that when user namespacing is used file ownership on disk reflects this, and all of the container's
|
||||
files and directories are owned by the container's effective user and group IDs. This means that copying files
|
||||
from and to the container image requires correction of the numeric UID/GID values, according to the UID/GID
|
||||
shift applied.</para></listitem>
|
||||
</varlistentry>
|
||||
|
||||
<varlistentry>
|
||||
|
||||
@@ -1737,7 +1737,7 @@ int btrfs_subvol_snapshot_fd(int old_fd, const char *new_path, BtrfsSnapshotFlag
|
||||
} else if (r < 0)
|
||||
return r;
|
||||
|
||||
r = copy_directory_fd(old_fd, new_path, true);
|
||||
r = copy_directory_fd(old_fd, new_path, COPY_MERGE|COPY_REFLINK);
|
||||
if (r < 0)
|
||||
goto fallback_fail;
|
||||
|
||||
|
||||
+89
-40
@@ -45,6 +45,7 @@
|
||||
#include "strv.h"
|
||||
#include "time-util.h"
|
||||
#include "umask-util.h"
|
||||
#include "user-util.h"
|
||||
#include "xattr-util.h"
|
||||
|
||||
#define COPY_BUFFER_SIZE (16*1024u)
|
||||
@@ -68,7 +69,7 @@ static ssize_t try_copy_file_range(int fd_in, loff_t *off_in,
|
||||
return -errno;
|
||||
}
|
||||
|
||||
int copy_bytes(int fdf, int fdt, uint64_t max_bytes, bool try_reflink) {
|
||||
int copy_bytes(int fdf, int fdt, uint64_t max_bytes, CopyFlags copy_flags) {
|
||||
bool try_cfr = true, try_sendfile = true, try_splice = true;
|
||||
int r;
|
||||
size_t m = SSIZE_MAX; /* that is the maximum that sendfile and c_f_r accept */
|
||||
@@ -77,7 +78,7 @@ int copy_bytes(int fdf, int fdt, uint64_t max_bytes, bool try_reflink) {
|
||||
assert(fdt >= 0);
|
||||
|
||||
/* Try btrfs reflinks first. */
|
||||
if (try_reflink &&
|
||||
if ((copy_flags & COPY_REFLINK) &&
|
||||
max_bytes == (uint64_t) -1 &&
|
||||
lseek(fdf, 0, SEEK_CUR) == 0 &&
|
||||
lseek(fdt, 0, SEEK_CUR) == 0) {
|
||||
@@ -176,7 +177,16 @@ int copy_bytes(int fdf, int fdt, uint64_t max_bytes, bool try_reflink) {
|
||||
return 0; /* return 0 if we hit EOF earlier than the size limit */
|
||||
}
|
||||
|
||||
static int fd_copy_symlink(int df, const char *from, const struct stat *st, int dt, const char *to) {
|
||||
static int fd_copy_symlink(
|
||||
int df,
|
||||
const char *from,
|
||||
const struct stat *st,
|
||||
int dt,
|
||||
const char *to,
|
||||
uid_t override_uid,
|
||||
gid_t override_gid,
|
||||
CopyFlags copy_flags) {
|
||||
|
||||
_cleanup_free_ char *target = NULL;
|
||||
int r;
|
||||
|
||||
@@ -191,13 +201,25 @@ static int fd_copy_symlink(int df, const char *from, const struct stat *st, int
|
||||
if (symlinkat(target, dt, to) < 0)
|
||||
return -errno;
|
||||
|
||||
if (fchownat(dt, to, st->st_uid, st->st_gid, AT_SYMLINK_NOFOLLOW) < 0)
|
||||
if (fchownat(dt, to,
|
||||
uid_is_valid(override_uid) ? override_uid : st->st_uid,
|
||||
gid_is_valid(override_gid) ? override_gid : st->st_gid,
|
||||
AT_SYMLINK_NOFOLLOW) < 0)
|
||||
return -errno;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int fd_copy_regular(int df, const char *from, const struct stat *st, int dt, const char *to) {
|
||||
static int fd_copy_regular(
|
||||
int df,
|
||||
const char *from,
|
||||
const struct stat *st,
|
||||
int dt,
|
||||
const char *to,
|
||||
uid_t override_uid,
|
||||
gid_t override_gid,
|
||||
CopyFlags copy_flags) {
|
||||
|
||||
_cleanup_close_ int fdf = -1, fdt = -1;
|
||||
struct timespec ts[2];
|
||||
int r, q;
|
||||
@@ -214,13 +236,15 @@ static int fd_copy_regular(int df, const char *from, const struct stat *st, int
|
||||
if (fdt < 0)
|
||||
return -errno;
|
||||
|
||||
r = copy_bytes(fdf, fdt, (uint64_t) -1, true);
|
||||
r = copy_bytes(fdf, fdt, (uint64_t) -1, copy_flags);
|
||||
if (r < 0) {
|
||||
unlinkat(dt, to, 0);
|
||||
return r;
|
||||
}
|
||||
|
||||
if (fchown(fdt, st->st_uid, st->st_gid) < 0)
|
||||
if (fchown(fdt,
|
||||
uid_is_valid(override_uid) ? override_uid : st->st_uid,
|
||||
gid_is_valid(override_gid) ? override_gid : st->st_gid) < 0)
|
||||
r = -errno;
|
||||
|
||||
if (fchmod(fdt, st->st_mode & 07777) < 0)
|
||||
@@ -229,7 +253,6 @@ static int fd_copy_regular(int df, const char *from, const struct stat *st, int
|
||||
ts[0] = st->st_atim;
|
||||
ts[1] = st->st_mtim;
|
||||
(void) futimens(fdt, ts);
|
||||
|
||||
(void) copy_xattr(fdf, fdt);
|
||||
|
||||
q = close(fdt);
|
||||
@@ -243,7 +266,15 @@ static int fd_copy_regular(int df, const char *from, const struct stat *st, int
|
||||
return r;
|
||||
}
|
||||
|
||||
static int fd_copy_fifo(int df, const char *from, const struct stat *st, int dt, const char *to) {
|
||||
static int fd_copy_fifo(
|
||||
int df,
|
||||
const char *from,
|
||||
const struct stat *st,
|
||||
int dt,
|
||||
const char *to,
|
||||
uid_t override_uid,
|
||||
gid_t override_gid,
|
||||
CopyFlags copy_flags) {
|
||||
int r;
|
||||
|
||||
assert(from);
|
||||
@@ -254,7 +285,10 @@ static int fd_copy_fifo(int df, const char *from, const struct stat *st, int dt,
|
||||
if (r < 0)
|
||||
return -errno;
|
||||
|
||||
if (fchownat(dt, to, st->st_uid, st->st_gid, AT_SYMLINK_NOFOLLOW) < 0)
|
||||
if (fchownat(dt, to,
|
||||
uid_is_valid(override_uid) ? override_uid : st->st_uid,
|
||||
gid_is_valid(override_gid) ? override_gid : st->st_gid,
|
||||
AT_SYMLINK_NOFOLLOW) < 0)
|
||||
r = -errno;
|
||||
|
||||
if (fchmodat(dt, to, st->st_mode & 07777, 0) < 0)
|
||||
@@ -263,7 +297,15 @@ static int fd_copy_fifo(int df, const char *from, const struct stat *st, int dt,
|
||||
return r;
|
||||
}
|
||||
|
||||
static int fd_copy_node(int df, const char *from, const struct stat *st, int dt, const char *to) {
|
||||
static int fd_copy_node(
|
||||
int df,
|
||||
const char *from,
|
||||
const struct stat *st,
|
||||
int dt,
|
||||
const char *to,
|
||||
uid_t override_uid,
|
||||
gid_t override_gid,
|
||||
CopyFlags copy_flags) {
|
||||
int r;
|
||||
|
||||
assert(from);
|
||||
@@ -274,7 +316,10 @@ static int fd_copy_node(int df, const char *from, const struct stat *st, int dt,
|
||||
if (r < 0)
|
||||
return -errno;
|
||||
|
||||
if (fchownat(dt, to, st->st_uid, st->st_gid, AT_SYMLINK_NOFOLLOW) < 0)
|
||||
if (fchownat(dt, to,
|
||||
uid_is_valid(override_uid) ? override_uid : st->st_uid,
|
||||
gid_is_valid(override_gid) ? override_gid : st->st_gid,
|
||||
AT_SYMLINK_NOFOLLOW) < 0)
|
||||
r = -errno;
|
||||
|
||||
if (fchmodat(dt, to, st->st_mode & 07777, 0) < 0)
|
||||
@@ -290,7 +335,9 @@ static int fd_copy_directory(
|
||||
int dt,
|
||||
const char *to,
|
||||
dev_t original_device,
|
||||
bool merge) {
|
||||
uid_t override_uid,
|
||||
gid_t override_gid,
|
||||
CopyFlags copy_flags) {
|
||||
|
||||
_cleanup_close_ int fdf = -1, fdt = -1;
|
||||
_cleanup_closedir_ DIR *d = NULL;
|
||||
@@ -316,7 +363,7 @@ static int fd_copy_directory(
|
||||
r = mkdirat(dt, to, st->st_mode & 07777);
|
||||
if (r >= 0)
|
||||
created = true;
|
||||
else if (errno == EEXIST && merge)
|
||||
else if (errno == EEXIST && (copy_flags & COPY_MERGE))
|
||||
created = false;
|
||||
else
|
||||
return -errno;
|
||||
@@ -343,19 +390,19 @@ static int fd_copy_directory(
|
||||
continue;
|
||||
|
||||
if (S_ISREG(buf.st_mode))
|
||||
q = fd_copy_regular(dirfd(d), de->d_name, &buf, fdt, de->d_name);
|
||||
q = fd_copy_regular(dirfd(d), de->d_name, &buf, fdt, de->d_name, override_uid, override_gid, copy_flags);
|
||||
else if (S_ISDIR(buf.st_mode))
|
||||
q = fd_copy_directory(dirfd(d), de->d_name, &buf, fdt, de->d_name, original_device, merge);
|
||||
q = fd_copy_directory(dirfd(d), de->d_name, &buf, fdt, de->d_name, original_device, override_uid, override_gid, copy_flags);
|
||||
else if (S_ISLNK(buf.st_mode))
|
||||
q = fd_copy_symlink(dirfd(d), de->d_name, &buf, fdt, de->d_name);
|
||||
q = fd_copy_symlink(dirfd(d), de->d_name, &buf, fdt, de->d_name, override_uid, override_gid, copy_flags);
|
||||
else if (S_ISFIFO(buf.st_mode))
|
||||
q = fd_copy_fifo(dirfd(d), de->d_name, &buf, fdt, de->d_name);
|
||||
q = fd_copy_fifo(dirfd(d), de->d_name, &buf, fdt, de->d_name, override_uid, override_gid, copy_flags);
|
||||
else if (S_ISBLK(buf.st_mode) || S_ISCHR(buf.st_mode) || S_ISSOCK(buf.st_mode))
|
||||
q = fd_copy_node(dirfd(d), de->d_name, &buf, fdt, de->d_name);
|
||||
q = fd_copy_node(dirfd(d), de->d_name, &buf, fdt, de->d_name, override_uid, override_gid, copy_flags);
|
||||
else
|
||||
q = -EOPNOTSUPP;
|
||||
|
||||
if (q == -EEXIST && merge)
|
||||
if (q == -EEXIST && (copy_flags & COPY_MERGE))
|
||||
q = 0;
|
||||
|
||||
if (q < 0)
|
||||
@@ -368,7 +415,9 @@ static int fd_copy_directory(
|
||||
st->st_mtim
|
||||
};
|
||||
|
||||
if (fchown(fdt, st->st_uid, st->st_gid) < 0)
|
||||
if (fchown(fdt,
|
||||
uid_is_valid(override_uid) ? override_uid : st->st_uid,
|
||||
gid_is_valid(override_gid) ? override_gid : st->st_gid) < 0)
|
||||
r = -errno;
|
||||
|
||||
if (fchmod(fdt, st->st_mode & 07777) < 0)
|
||||
@@ -381,7 +430,7 @@ static int fd_copy_directory(
|
||||
return r;
|
||||
}
|
||||
|
||||
int copy_tree_at(int fdf, const char *from, int fdt, const char *to, bool merge) {
|
||||
int copy_tree_at(int fdf, const char *from, int fdt, const char *to, uid_t override_uid, gid_t override_gid, CopyFlags copy_flags) {
|
||||
struct stat st;
|
||||
|
||||
assert(from);
|
||||
@@ -391,24 +440,24 @@ int copy_tree_at(int fdf, const char *from, int fdt, const char *to, bool merge)
|
||||
return -errno;
|
||||
|
||||
if (S_ISREG(st.st_mode))
|
||||
return fd_copy_regular(fdf, from, &st, fdt, to);
|
||||
return fd_copy_regular(fdf, from, &st, fdt, to, override_uid, override_gid, copy_flags);
|
||||
else if (S_ISDIR(st.st_mode))
|
||||
return fd_copy_directory(fdf, from, &st, fdt, to, st.st_dev, merge);
|
||||
return fd_copy_directory(fdf, from, &st, fdt, to, st.st_dev, override_uid, override_gid, copy_flags);
|
||||
else if (S_ISLNK(st.st_mode))
|
||||
return fd_copy_symlink(fdf, from, &st, fdt, to);
|
||||
return fd_copy_symlink(fdf, from, &st, fdt, to, override_uid, override_gid, copy_flags);
|
||||
else if (S_ISFIFO(st.st_mode))
|
||||
return fd_copy_fifo(fdf, from, &st, fdt, to);
|
||||
return fd_copy_fifo(fdf, from, &st, fdt, to, override_uid, override_gid, copy_flags);
|
||||
else if (S_ISBLK(st.st_mode) || S_ISCHR(st.st_mode) || S_ISSOCK(st.st_mode))
|
||||
return fd_copy_node(fdf, from, &st, fdt, to);
|
||||
return fd_copy_node(fdf, from, &st, fdt, to, override_uid, override_gid, copy_flags);
|
||||
else
|
||||
return -EOPNOTSUPP;
|
||||
}
|
||||
|
||||
int copy_tree(const char *from, const char *to, bool merge) {
|
||||
return copy_tree_at(AT_FDCWD, from, AT_FDCWD, to, merge);
|
||||
int copy_tree(const char *from, const char *to, uid_t override_uid, gid_t override_gid, CopyFlags copy_flags) {
|
||||
return copy_tree_at(AT_FDCWD, from, AT_FDCWD, to, override_uid, override_gid, copy_flags);
|
||||
}
|
||||
|
||||
int copy_directory_fd(int dirfd, const char *to, bool merge) {
|
||||
int copy_directory_fd(int dirfd, const char *to, CopyFlags copy_flags) {
|
||||
struct stat st;
|
||||
|
||||
assert(dirfd >= 0);
|
||||
@@ -420,10 +469,10 @@ int copy_directory_fd(int dirfd, const char *to, bool merge) {
|
||||
if (!S_ISDIR(st.st_mode))
|
||||
return -ENOTDIR;
|
||||
|
||||
return fd_copy_directory(dirfd, NULL, &st, AT_FDCWD, to, st.st_dev, merge);
|
||||
return fd_copy_directory(dirfd, NULL, &st, AT_FDCWD, to, st.st_dev, UID_INVALID, GID_INVALID, copy_flags);
|
||||
}
|
||||
|
||||
int copy_directory(const char *from, const char *to, bool merge) {
|
||||
int copy_directory(const char *from, const char *to, CopyFlags copy_flags) {
|
||||
struct stat st;
|
||||
|
||||
assert(from);
|
||||
@@ -435,10 +484,10 @@ int copy_directory(const char *from, const char *to, bool merge) {
|
||||
if (!S_ISDIR(st.st_mode))
|
||||
return -ENOTDIR;
|
||||
|
||||
return fd_copy_directory(AT_FDCWD, from, &st, AT_FDCWD, to, st.st_dev, merge);
|
||||
return fd_copy_directory(AT_FDCWD, from, &st, AT_FDCWD, to, st.st_dev, UID_INVALID, GID_INVALID, copy_flags);
|
||||
}
|
||||
|
||||
int copy_file_fd(const char *from, int fdt, bool try_reflink) {
|
||||
int copy_file_fd(const char *from, int fdt, CopyFlags copy_flags) {
|
||||
_cleanup_close_ int fdf = -1;
|
||||
int r;
|
||||
|
||||
@@ -449,7 +498,7 @@ int copy_file_fd(const char *from, int fdt, bool try_reflink) {
|
||||
if (fdf < 0)
|
||||
return -errno;
|
||||
|
||||
r = copy_bytes(fdf, fdt, (uint64_t) -1, try_reflink);
|
||||
r = copy_bytes(fdf, fdt, (uint64_t) -1, copy_flags);
|
||||
|
||||
(void) copy_times(fdf, fdt);
|
||||
(void) copy_xattr(fdf, fdt);
|
||||
@@ -457,7 +506,7 @@ int copy_file_fd(const char *from, int fdt, bool try_reflink) {
|
||||
return r;
|
||||
}
|
||||
|
||||
int copy_file(const char *from, const char *to, int flags, mode_t mode, unsigned chattr_flags) {
|
||||
int copy_file(const char *from, const char *to, int flags, mode_t mode, unsigned chattr_flags, CopyFlags copy_flags) {
|
||||
int fdt = -1, r;
|
||||
|
||||
assert(from);
|
||||
@@ -472,7 +521,7 @@ int copy_file(const char *from, const char *to, int flags, mode_t mode, unsigned
|
||||
if (chattr_flags != 0)
|
||||
(void) chattr_fd(fdt, chattr_flags, (unsigned) -1);
|
||||
|
||||
r = copy_file_fd(from, fdt, true);
|
||||
r = copy_file_fd(from, fdt, copy_flags);
|
||||
if (r < 0) {
|
||||
close(fdt);
|
||||
unlink(to);
|
||||
@@ -487,7 +536,7 @@ int copy_file(const char *from, const char *to, int flags, mode_t mode, unsigned
|
||||
return 0;
|
||||
}
|
||||
|
||||
int copy_file_atomic(const char *from, const char *to, mode_t mode, bool replace, unsigned chattr_flags) {
|
||||
int copy_file_atomic(const char *from, const char *to, mode_t mode, unsigned chattr_flags, CopyFlags copy_flags) {
|
||||
_cleanup_free_ char *t = NULL;
|
||||
int r;
|
||||
|
||||
@@ -498,11 +547,11 @@ int copy_file_atomic(const char *from, const char *to, mode_t mode, bool replace
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
r = copy_file(from, t, O_NOFOLLOW|O_EXCL, mode, chattr_flags);
|
||||
r = copy_file(from, t, O_NOFOLLOW|O_EXCL, mode, chattr_flags, copy_flags);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
if (replace) {
|
||||
if (copy_flags & COPY_REPLACE) {
|
||||
r = renameat(AT_FDCWD, t, AT_FDCWD, to);
|
||||
if (r < 0)
|
||||
r = -errno;
|
||||
|
||||
+14
-8
@@ -24,13 +24,19 @@
|
||||
#include <stdint.h>
|
||||
#include <sys/types.h>
|
||||
|
||||
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, unsigned chattr_flags);
|
||||
int copy_file_atomic(const char *from, const char *to, mode_t mode, bool replace, unsigned chattr_flags);
|
||||
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);
|
||||
int copy_directory(const char *from, const char *to, bool merge);
|
||||
int copy_bytes(int fdf, int fdt, uint64_t max_bytes, bool try_reflink);
|
||||
typedef enum CopyFlags {
|
||||
COPY_REFLINK = 0x1, /* try to reflink */
|
||||
COPY_MERGE = 0x2, /* merge existing trees with our new one to copy */
|
||||
COPY_REPLACE = 0x4, /* replace an existing file if there's one */
|
||||
} CopyFlags;
|
||||
|
||||
int copy_file_fd(const char *from, int to, CopyFlags copy_flags);
|
||||
int copy_file(const char *from, const char *to, int open_flags, mode_t mode, unsigned chattr_flags, CopyFlags copy_flags);
|
||||
int copy_file_atomic(const char *from, const char *to, mode_t mode, unsigned chattr_flags, CopyFlags copy_flags);
|
||||
int copy_tree(const char *from, const char *to, uid_t override_uid, gid_t override_gid, CopyFlags copy_flags);
|
||||
int copy_tree_at(int fdf, const char *from, int fdt, const char *to, uid_t override_uid, gid_t override_gid, CopyFlags copy_flags);
|
||||
int copy_directory_fd(int dirfd, const char *to, CopyFlags copy_flags);
|
||||
int copy_directory(const char *from, const char *to, CopyFlags copy_flags);
|
||||
int copy_bytes(int fdf, int fdt, uint64_t max_bytes, CopyFlags copy_flags);
|
||||
int copy_times(int fdf, int fdt);
|
||||
int copy_xattr(int fdf, int fdt);
|
||||
|
||||
+2
-2
@@ -1340,11 +1340,11 @@ static int usbffs_write_descs(int fd, Service *s) {
|
||||
if (!s->usb_function_descriptors || !s->usb_function_strings)
|
||||
return -EINVAL;
|
||||
|
||||
r = copy_file_fd(s->usb_function_descriptors, fd, false);
|
||||
r = copy_file_fd(s->usb_function_descriptors, fd, 0);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
return copy_file_fd(s->usb_function_strings, fd, false);
|
||||
return copy_file_fd(s->usb_function_strings, fd, 0);
|
||||
}
|
||||
|
||||
static int usbffs_select_ep(const struct dirent *d) {
|
||||
|
||||
@@ -352,7 +352,7 @@ static int save_external_coredump(
|
||||
if (fd < 0)
|
||||
return log_error_errno(fd, "Failed to create temporary file for coredump %s: %m", fn);
|
||||
|
||||
r = copy_bytes(input_fd, fd, max_size, false);
|
||||
r = copy_bytes(input_fd, fd, max_size, 0);
|
||||
if (r < 0) {
|
||||
log_error_errno(r, "Cannot store coredump of %s (%s): %m", context[CONTEXT_PID], context[CONTEXT_COMM]);
|
||||
goto fail;
|
||||
|
||||
@@ -252,7 +252,7 @@ static int process_locale(void) {
|
||||
if (arg_copy_locale && arg_root) {
|
||||
|
||||
mkdir_parents(etc_localeconf, 0755);
|
||||
r = copy_file("/etc/locale.conf", etc_localeconf, 0, 0644, 0);
|
||||
r = copy_file("/etc/locale.conf", etc_localeconf, 0, 0644, 0, COPY_REFLINK);
|
||||
if (r != -ENOENT) {
|
||||
if (r < 0)
|
||||
return log_error_errno(r, "Failed to copy %s: %m", etc_localeconf);
|
||||
|
||||
@@ -315,7 +315,7 @@ static int raw_pull_copy_auxiliary_file(
|
||||
|
||||
local = strjoina(i->image_root, "/", i->local, suffix);
|
||||
|
||||
r = copy_file_atomic(*path, local, 0644, i->force_local, 0);
|
||||
r = copy_file_atomic(*path, local, 0644, 0, COPY_REFLINK | (i->force_local ? COPY_REPLACE : 0));
|
||||
if (r == -EEXIST)
|
||||
log_warning_errno(r, "File %s already exists, not replacing.", local);
|
||||
else if (r == -ENOENT)
|
||||
@@ -378,7 +378,7 @@ static int raw_pull_make_local_copy(RawPull *i) {
|
||||
if (r < 0)
|
||||
log_warning_errno(r, "Failed to set file attributes on %s: %m", tp);
|
||||
|
||||
r = copy_bytes(i->raw_job->disk_fd, dfd, (uint64_t) -1, true);
|
||||
r = copy_bytes(i->raw_job->disk_fd, dfd, (uint64_t) -1, COPY_REFLINK);
|
||||
if (r < 0) {
|
||||
unlink(tp);
|
||||
return log_error_errno(r, "Failed to make writable copy of image: %m");
|
||||
|
||||
@@ -256,7 +256,7 @@ static int tar_pull_make_local_copy(TarPull *i) {
|
||||
|
||||
local_settings = strjoina(i->image_root, "/", i->local, ".nspawn");
|
||||
|
||||
r = copy_file_atomic(i->settings_path, local_settings, 0664, i->force_local, 0);
|
||||
r = copy_file_atomic(i->settings_path, local_settings, 0664, 0, COPY_REFLINK | (i->force_local ? COPY_REPLACE : 0));
|
||||
if (r == -EEXIST)
|
||||
log_warning_errno(r, "Settings file %s already exists, not replacing.", local_settings);
|
||||
else if (r == -ENOENT)
|
||||
|
||||
@@ -374,7 +374,7 @@ static int raw_image_get_os_release(Image *image, char ***ret, sd_bus_error *err
|
||||
if (fd < 0)
|
||||
_exit(EXIT_FAILURE);
|
||||
|
||||
r = copy_bytes(fd, pair[1], (uint64_t) -1, false);
|
||||
r = copy_bytes(fd, pair[1], (uint64_t) -1, 0);
|
||||
if (r < 0)
|
||||
_exit(EXIT_FAILURE);
|
||||
|
||||
|
||||
@@ -411,7 +411,7 @@ int bus_machine_method_get_os_release(sd_bus_message *message, void *userdata, s
|
||||
if (fd < 0)
|
||||
_exit(EXIT_FAILURE);
|
||||
|
||||
r = copy_bytes(fd, pair[1], (uint64_t) -1, false);
|
||||
r = copy_bytes(fd, pair[1], (uint64_t) -1, 0);
|
||||
if (r < 0)
|
||||
_exit(EXIT_FAILURE);
|
||||
|
||||
@@ -841,6 +841,7 @@ int bus_machine_method_bind_mount(sd_bus_message *message, void *userdata, sd_bu
|
||||
int read_only, make_directory;
|
||||
pid_t child;
|
||||
siginfo_t si;
|
||||
uid_t uid;
|
||||
int r;
|
||||
|
||||
assert(message);
|
||||
@@ -875,6 +876,12 @@ int bus_machine_method_bind_mount(sd_bus_message *message, void *userdata, sd_bu
|
||||
if (r == 0)
|
||||
return 1; /* Will call us back */
|
||||
|
||||
r = machine_get_uid_shift(m, &uid);
|
||||
if (r < 0)
|
||||
return r;
|
||||
if (uid != 0)
|
||||
return sd_bus_error_setf(error, SD_BUS_ERROR_NOT_SUPPORTED, "Can't bind mount on container with user namespacing applied.");
|
||||
|
||||
/* One day, when bind mounting /proc/self/fd/n works across
|
||||
* namespace boundaries we should rework this logic to make
|
||||
* use of it... */
|
||||
@@ -1055,10 +1062,12 @@ finish:
|
||||
int bus_machine_method_copy(sd_bus_message *message, void *userdata, sd_bus_error *error) {
|
||||
const char *src, *dest, *host_path, *container_path, *host_basename, *host_dirname, *container_basename, *container_dirname;
|
||||
_cleanup_close_pair_ int errno_pipe_fd[2] = { -1, -1 };
|
||||
CopyFlags copy_flags = COPY_REFLINK|COPY_MERGE;
|
||||
_cleanup_close_ int hostfd = -1;
|
||||
Machine *m = userdata;
|
||||
bool copy_from;
|
||||
pid_t child;
|
||||
uid_t uid_shift;
|
||||
char *t;
|
||||
int r;
|
||||
|
||||
@@ -1097,6 +1106,10 @@ int bus_machine_method_copy(sd_bus_message *message, void *userdata, sd_bus_erro
|
||||
if (r == 0)
|
||||
return 1; /* Will call us back */
|
||||
|
||||
r = machine_get_uid_shift(m, &uid_shift);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
copy_from = strstr(sd_bus_message_get_member(message), "CopyFrom");
|
||||
|
||||
if (copy_from) {
|
||||
@@ -1151,10 +1164,13 @@ int bus_machine_method_copy(sd_bus_message *message, void *userdata, sd_bus_erro
|
||||
goto child_fail;
|
||||
}
|
||||
|
||||
/* Run the actual copy operation. Note that when an UID shift is set we'll either clamp the UID/GID to
|
||||
* 0 or to the actual UID shift depending on the direction we copy. If no UID shift is set we'll copy
|
||||
* the UID/GIDs as they are. */
|
||||
if (copy_from)
|
||||
r = copy_tree_at(containerfd, container_basename, hostfd, host_basename, true);
|
||||
r = copy_tree_at(containerfd, container_basename, hostfd, host_basename, uid_shift == 0 ? UID_INVALID : 0, uid_shift == 0 ? GID_INVALID : 0, copy_flags);
|
||||
else
|
||||
r = copy_tree_at(hostfd, host_basename, containerfd, container_basename, true);
|
||||
r = copy_tree_at(hostfd, host_basename, containerfd, container_basename, uid_shift == 0 ? UID_INVALID : uid_shift, uid_shift == 0 ? GID_INVALID : uid_shift, copy_flags);
|
||||
|
||||
hostfd = safe_close(hostfd);
|
||||
containerfd = safe_close(containerfd);
|
||||
@@ -1276,6 +1292,32 @@ int bus_machine_method_open_root_directory(sd_bus_message *message, void *userda
|
||||
return sd_bus_reply_method_return(message, "h", fd);
|
||||
}
|
||||
|
||||
int bus_machine_method_get_uid_shift(sd_bus_message *message, void *userdata, sd_bus_error *error) {
|
||||
Machine *m = userdata;
|
||||
uid_t shift = 0;
|
||||
int r;
|
||||
|
||||
assert(message);
|
||||
assert(m);
|
||||
|
||||
/* You wonder why this is a method and not a property? Well, properties are not supposed to return errors, but
|
||||
* we kinda have to for this. */
|
||||
|
||||
if (m->class == MACHINE_HOST)
|
||||
return sd_bus_reply_method_return(message, "u", UINT32_C(0));
|
||||
|
||||
if (m->class != MACHINE_CONTAINER)
|
||||
return sd_bus_error_setf(error, SD_BUS_ERROR_NOT_SUPPORTED, "UID/GID shift may only be determined for container machines.");
|
||||
|
||||
r = machine_get_uid_shift(m, &shift);
|
||||
if (r == -ENXIO)
|
||||
return sd_bus_error_setf(error, SD_BUS_ERROR_NOT_SUPPORTED, "Machine %s uses a complex UID/GID mapping, cannot determine shift", m->name);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
return sd_bus_reply_method_return(message, "u", (uint32_t) shift);
|
||||
}
|
||||
|
||||
const sd_bus_vtable machine_vtable[] = {
|
||||
SD_BUS_VTABLE_START(0),
|
||||
SD_BUS_PROPERTY("Name", "s", NULL, offsetof(Machine, name), SD_BUS_VTABLE_PROPERTY_CONST),
|
||||
@@ -1293,6 +1335,7 @@ const sd_bus_vtable machine_vtable[] = {
|
||||
SD_BUS_METHOD("Kill", "si", NULL, bus_machine_method_kill, SD_BUS_VTABLE_UNPRIVILEGED),
|
||||
SD_BUS_METHOD("GetAddresses", NULL, "a(iay)", bus_machine_method_get_addresses, SD_BUS_VTABLE_UNPRIVILEGED),
|
||||
SD_BUS_METHOD("GetOSRelease", NULL, "a{ss}", bus_machine_method_get_os_release, SD_BUS_VTABLE_UNPRIVILEGED),
|
||||
SD_BUS_METHOD("GetUIDShift", NULL, "u", bus_machine_method_get_uid_shift, SD_BUS_VTABLE_UNPRIVILEGED),
|
||||
SD_BUS_METHOD("OpenPTY", NULL, "hs", bus_machine_method_open_pty, SD_BUS_VTABLE_UNPRIVILEGED),
|
||||
SD_BUS_METHOD("OpenLogin", NULL, "hs", bus_machine_method_open_login, SD_BUS_VTABLE_UNPRIVILEGED),
|
||||
SD_BUS_METHOD("OpenShell", "ssasas", "hs", bus_machine_method_open_shell, SD_BUS_VTABLE_UNPRIVILEGED),
|
||||
|
||||
@@ -39,6 +39,7 @@ int bus_machine_method_open_shell(sd_bus_message *message, void *userdata, sd_bu
|
||||
int bus_machine_method_bind_mount(sd_bus_message *message, void *userdata, sd_bus_error *error);
|
||||
int bus_machine_method_copy(sd_bus_message *message, void *userdata, sd_bus_error *error);
|
||||
int bus_machine_method_open_root_directory(sd_bus_message *message, void *userdata, sd_bus_error *error);
|
||||
int bus_machine_method_get_uid_shift(sd_bus_message *message, void *userdata, sd_bus_error *error);
|
||||
|
||||
int machine_send_signal(Machine *m, bool new_machine);
|
||||
int machine_send_create_reply(Machine *m, sd_bus_error *error);
|
||||
|
||||
@@ -38,6 +38,7 @@
|
||||
#include "parse-util.h"
|
||||
#include "process-util.h"
|
||||
#include "special.h"
|
||||
#include "stdio-util.h"
|
||||
#include "string-table.h"
|
||||
#include "terminal-util.h"
|
||||
#include "unit-name.h"
|
||||
@@ -604,6 +605,96 @@ void machine_release_unit(Machine *m) {
|
||||
m->unit = mfree(m->unit);
|
||||
}
|
||||
|
||||
int machine_get_uid_shift(Machine *m, uid_t *ret) {
|
||||
char p[strlen("/proc//uid_map") + DECIMAL_STR_MAX(pid_t) + 1];
|
||||
uid_t uid_base, uid_shift, uid_range;
|
||||
gid_t gid_base, gid_shift, gid_range;
|
||||
_cleanup_fclose_ FILE *f = NULL;
|
||||
int k;
|
||||
|
||||
assert(m);
|
||||
assert(ret);
|
||||
|
||||
/* Return the base UID/GID of the specified machine. Note that this only works for containers with simple
|
||||
* mappings. In most cases setups should be simple like this, and administrators should only care about the
|
||||
* basic offset a container has relative to the host. This is what this function exposes.
|
||||
*
|
||||
* If we encounter any more complex mappings we politely refuse this with ENXIO. */
|
||||
|
||||
if (m->class == MACHINE_HOST) {
|
||||
*ret = 0;
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (m->class != MACHINE_CONTAINER)
|
||||
return -EOPNOTSUPP;
|
||||
|
||||
xsprintf(p, "/proc/" PID_FMT "/uid_map", m->leader);
|
||||
f = fopen(p, "re");
|
||||
if (!f) {
|
||||
if (errno == ENOENT) {
|
||||
/* If the file doesn't exist, user namespacing is off in the kernel, return a zero mapping hence. */
|
||||
*ret = 0;
|
||||
return 0;
|
||||
}
|
||||
|
||||
return -errno;
|
||||
}
|
||||
|
||||
/* Read the first line. There's at least one. */
|
||||
errno = 0;
|
||||
k = fscanf(f, UID_FMT " " UID_FMT " " UID_FMT "\n", &uid_base, &uid_shift, &uid_range);
|
||||
if (k != 3) {
|
||||
if (ferror(f))
|
||||
return -errno;
|
||||
|
||||
return -EBADMSG;
|
||||
}
|
||||
|
||||
/* Not a mapping starting at 0? Then it's a complex mapping we can't expose here. */
|
||||
if (uid_base != 0)
|
||||
return -ENXIO;
|
||||
/* Insist that at least the nobody user is mapped, everything else is weird, and hence complex, and we don't support it */
|
||||
if (uid_range < (uid_t) 65534U)
|
||||
return -ENXIO;
|
||||
|
||||
/* If there's more than one line, then we don't support this mapping. */
|
||||
if (fgetc(f) != EOF)
|
||||
return -ENXIO;
|
||||
|
||||
fclose(f);
|
||||
|
||||
xsprintf(p, "/proc/" PID_FMT "/gid_map", m->leader);
|
||||
f = fopen(p, "re");
|
||||
if (!f)
|
||||
return -errno;
|
||||
|
||||
/* Read the first line. There's at least one. */
|
||||
errno = 0;
|
||||
k = fscanf(f, GID_FMT " " GID_FMT " " GID_FMT "\n", &gid_base, &gid_shift, &gid_range);
|
||||
if (k != 3) {
|
||||
if (ferror(f))
|
||||
return -errno;
|
||||
|
||||
return -EBADMSG;
|
||||
}
|
||||
|
||||
/* If there's more than one line, then we don't support this file. */
|
||||
if (fgetc(f) != EOF)
|
||||
return -ENXIO;
|
||||
|
||||
/* If the UID and GID mapping doesn't match, we don't support this mapping. */
|
||||
if (uid_base != (uid_t) gid_base)
|
||||
return -ENXIO;
|
||||
if (uid_shift != (uid_t) gid_shift)
|
||||
return -ENXIO;
|
||||
if (uid_range != (uid_t) gid_range)
|
||||
return -ENXIO;
|
||||
|
||||
*ret = uid_shift;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const char* const machine_class_table[_MACHINE_CLASS_MAX] = {
|
||||
[MACHINE_CONTAINER] = "container",
|
||||
[MACHINE_VM] = "vm",
|
||||
|
||||
@@ -108,3 +108,5 @@ KillWho kill_who_from_string(const char *s) _pure_;
|
||||
|
||||
int machine_openpt(Machine *m, int flags);
|
||||
int machine_open_terminal(Machine *m, const char *path, int mode);
|
||||
|
||||
int machine_get_uid_shift(Machine *m, uid_t *ret);
|
||||
|
||||
@@ -327,8 +327,10 @@ static int list_machines(int argc, char *argv[], void *userdata) {
|
||||
(int) max_version_id, strdash_if_empty(machines[j].version_id));
|
||||
|
||||
r = print_addresses(bus, machines[j].name, 0, "", prefix, arg_addrs);
|
||||
if (r == -EOPNOTSUPP)
|
||||
printf("-\n");
|
||||
if (r <= 0) /* error or no addresses defined? */
|
||||
fputs("-\n", stdout);
|
||||
else
|
||||
fputc('\n', stdout);
|
||||
}
|
||||
|
||||
if (arg_legend) {
|
||||
@@ -520,6 +522,7 @@ static int print_addresses(sd_bus *bus, const char *name, int ifi, const char *p
|
||||
_cleanup_(sd_bus_message_unrefp) sd_bus_message *reply = NULL;
|
||||
_cleanup_free_ char *addresses = NULL;
|
||||
bool truncate = false;
|
||||
unsigned n = 0;
|
||||
int r;
|
||||
|
||||
assert(bus);
|
||||
@@ -567,7 +570,7 @@ static int print_addresses(sd_bus *bus, const char *name, int ifi, const char *p
|
||||
else
|
||||
strcpy(buf_ifi, "");
|
||||
|
||||
if(!strextend(&addresses, prefix, inet_ntop(family, a, buffer, sizeof(buffer)), buf_ifi, NULL))
|
||||
if (!strextend(&addresses, prefix, inet_ntop(family, a, buffer, sizeof(buffer)), buf_ifi, NULL))
|
||||
return log_oom();
|
||||
} else
|
||||
truncate = true;
|
||||
@@ -581,6 +584,8 @@ static int print_addresses(sd_bus *bus, const char *name, int ifi, const char *p
|
||||
|
||||
if (n_addr > 0)
|
||||
n_addr -= 1;
|
||||
|
||||
n++;
|
||||
}
|
||||
if (r < 0)
|
||||
return bus_log_parse_error(r);
|
||||
@@ -589,8 +594,10 @@ static int print_addresses(sd_bus *bus, const char *name, int ifi, const char *p
|
||||
if (r < 0)
|
||||
return bus_log_parse_error(r);
|
||||
|
||||
fprintf(stdout, "%s%s\n", addresses, truncate ? "..." : "");
|
||||
return 0;
|
||||
if (n > 0)
|
||||
fprintf(stdout, "%s%s", addresses, truncate ? "..." : "");
|
||||
|
||||
return (int) n;
|
||||
}
|
||||
|
||||
static int print_os_release(sd_bus *bus, const char *method, const char *name, const char *prefix) {
|
||||
@@ -611,6 +618,37 @@ static int print_os_release(sd_bus *bus, const char *method, const char *name, c
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int print_uid_shift(sd_bus *bus, const char *name) {
|
||||
_cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
|
||||
_cleanup_(sd_bus_message_unrefp) sd_bus_message *reply = NULL;
|
||||
uint32_t shift;
|
||||
int r;
|
||||
|
||||
assert(bus);
|
||||
assert(name);
|
||||
|
||||
r = sd_bus_call_method(bus,
|
||||
"org.freedesktop.machine1",
|
||||
"/org/freedesktop/machine1",
|
||||
"org.freedesktop.machine1.Manager",
|
||||
"GetMachineUIDShift",
|
||||
&error,
|
||||
&reply,
|
||||
"s", name);
|
||||
if (r < 0)
|
||||
return log_debug_errno(r, "Failed to query UID/GID shift: %s", bus_error_message(&error, r));
|
||||
|
||||
r = sd_bus_message_read(reply, "u", &shift);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
if (shift == 0) /* Don't show trivial mappings */
|
||||
return 0;
|
||||
|
||||
printf(" UID Shift: %" PRIu32 "\n", shift);
|
||||
return 0;
|
||||
}
|
||||
|
||||
typedef struct MachineStatusInfo {
|
||||
char *name;
|
||||
sd_id128_t id;
|
||||
@@ -707,13 +745,16 @@ static void print_machine_status_info(sd_bus *bus, MachineStatusInfo *i) {
|
||||
fputc('\n', stdout);
|
||||
}
|
||||
|
||||
print_addresses(bus, i->name, ifi,
|
||||
"\t Address: ",
|
||||
"\n\t ",
|
||||
ALL_IP_ADDRESSES);
|
||||
if (print_addresses(bus, i->name, ifi,
|
||||
"\t Address: ",
|
||||
"\n\t ",
|
||||
ALL_IP_ADDRESSES) > 0)
|
||||
fputc('\n', stdout);
|
||||
|
||||
print_os_release(bus, "GetMachineOSRelease", i->name, "\t OS: ");
|
||||
|
||||
print_uid_shift(bus, i->name);
|
||||
|
||||
if (i->unit) {
|
||||
printf("\t Unit: %s\n", i->unit);
|
||||
show_unit_cgroup(bus, i->unit, i->leader);
|
||||
|
||||
@@ -729,6 +729,26 @@ static int method_open_machine_root_directory(sd_bus_message *message, void *use
|
||||
return bus_machine_method_open_root_directory(message, machine, error);
|
||||
}
|
||||
|
||||
static int method_get_machine_uid_shift(sd_bus_message *message, void *userdata, sd_bus_error *error) {
|
||||
Manager *m = userdata;
|
||||
Machine *machine;
|
||||
const char *name;
|
||||
int r;
|
||||
|
||||
assert(message);
|
||||
assert(m);
|
||||
|
||||
r = sd_bus_message_read(message, "s", &name);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
machine = hashmap_get(m->machines, name);
|
||||
if (!machine)
|
||||
return sd_bus_error_setf(error, BUS_ERROR_NO_SUCH_MACHINE, "No machine '%s' known", name);
|
||||
|
||||
return bus_machine_method_get_uid_shift(message, machine, error);
|
||||
}
|
||||
|
||||
static int method_remove_image(sd_bus_message *message, void *userdata, sd_bus_error *error) {
|
||||
_cleanup_(image_unrefp) Image* i = NULL;
|
||||
const char *name;
|
||||
@@ -1416,6 +1436,7 @@ const sd_bus_vtable manager_vtable[] = {
|
||||
SD_BUS_METHOD("CopyFromMachine", "sss", NULL, method_copy_machine, SD_BUS_VTABLE_UNPRIVILEGED),
|
||||
SD_BUS_METHOD("CopyToMachine", "sss", NULL, method_copy_machine, SD_BUS_VTABLE_UNPRIVILEGED),
|
||||
SD_BUS_METHOD("OpenMachineRootDirectory", "s", "h", method_open_machine_root_directory, SD_BUS_VTABLE_UNPRIVILEGED),
|
||||
SD_BUS_METHOD("GetMachineUIDShift", "s", "u", method_get_machine_uid_shift, SD_BUS_VTABLE_UNPRIVILEGED),
|
||||
SD_BUS_METHOD("RemoveImage", "s", NULL, method_remove_image, SD_BUS_VTABLE_UNPRIVILEGED),
|
||||
SD_BUS_METHOD("RenameImage", "ss", NULL, method_rename_image, SD_BUS_VTABLE_UNPRIVILEGED),
|
||||
SD_BUS_METHOD("CloneImage", "ssb", NULL, method_clone_image, SD_BUS_VTABLE_UNPRIVILEGED),
|
||||
|
||||
@@ -61,8 +61,10 @@ static int operation_done(sd_event_source *s, const siginfo_t *si, void *userdat
|
||||
} else {
|
||||
/* The default operation when done is to simply return an error on failure or an empty success
|
||||
* message on success. */
|
||||
if (r < 0)
|
||||
if (r < 0) {
|
||||
sd_bus_error_set_errno(&error, r);
|
||||
goto fail;
|
||||
}
|
||||
|
||||
r = sd_bus_reply_method_return(o->message, NULL);
|
||||
if (r < 0)
|
||||
|
||||
@@ -64,6 +64,10 @@
|
||||
send_interface="org.freedesktop.machine1.Manager"
|
||||
send_member="GetMachineOSRelease"/>
|
||||
|
||||
<allow send_destination="org.freedesktop.machine1"
|
||||
send_interface="org.freedesktop.machine1.Manager"
|
||||
send_member="GetMachineUIDShift"/>
|
||||
|
||||
<allow send_destination="org.freedesktop.machine1"
|
||||
send_interface="org.freedesktop.machine1.Manager"
|
||||
send_member="OpenMachineLogin"/>
|
||||
@@ -148,6 +152,10 @@
|
||||
send_interface="org.freedesktop.machine1.Machine"
|
||||
send_member="GetOSRelease"/>
|
||||
|
||||
<allow send_destination="org.freedesktop.machine1"
|
||||
send_interface="org.freedesktop.machine1.Machine"
|
||||
send_member="GetUIDShift"/>
|
||||
|
||||
<allow send_destination="org.freedesktop.machine1"
|
||||
send_interface="org.freedesktop.machine1.Machine"
|
||||
send_member="OpenLogin"/>
|
||||
|
||||
+3
-3
@@ -1364,7 +1364,7 @@ static int setup_resolv_conf(const char *dest) {
|
||||
}
|
||||
|
||||
/* If that didn't work, let's copy the file */
|
||||
r = copy_file("/etc/resolv.conf", where, O_TRUNC|O_NOFOLLOW, 0644, 0);
|
||||
r = copy_file("/etc/resolv.conf", where, O_TRUNC|O_NOFOLLOW, 0644, 0, COPY_REFLINK);
|
||||
if (r < 0) {
|
||||
/* If the file already exists as symlink, let's suppress the warning, under the assumption that
|
||||
* resolved or something similar runs inside and the symlink points there.
|
||||
@@ -3700,7 +3700,7 @@ int main(int argc, char *argv[]) {
|
||||
goto finish;
|
||||
}
|
||||
|
||||
r = copy_file(arg_image, np, O_EXCL, arg_read_only ? 0400 : 0600, FS_NOCOW_FL);
|
||||
r = copy_file(arg_image, np, O_EXCL, arg_read_only ? 0400 : 0600, FS_NOCOW_FL, COPY_REFLINK);
|
||||
if (r < 0) {
|
||||
r = log_error_errno(r, "Failed to copy image file: %m");
|
||||
goto finish;
|
||||
@@ -3856,7 +3856,7 @@ finish:
|
||||
|
||||
/* Try to flush whatever is still queued in the pty */
|
||||
if (master >= 0) {
|
||||
(void) copy_bytes(master, STDOUT_FILENO, (uint64_t) -1, false);
|
||||
(void) copy_bytes(master, STDOUT_FILENO, (uint64_t) -1, 0);
|
||||
master = safe_close(master);
|
||||
}
|
||||
|
||||
|
||||
@@ -594,7 +594,7 @@ static int clone_auxiliary_file(const char *path, const char *new_name, const ch
|
||||
if (!rs)
|
||||
return -ENOMEM;
|
||||
|
||||
return copy_file_atomic(path, rs, 0664, false, 0);
|
||||
return copy_file_atomic(path, rs, 0664, 0, COPY_REFLINK);
|
||||
}
|
||||
|
||||
int image_clone(Image *i, const char *new_name, bool read_only) {
|
||||
@@ -656,7 +656,7 @@ int image_clone(Image *i, const char *new_name, bool read_only) {
|
||||
case IMAGE_RAW:
|
||||
new_path = strjoina("/var/lib/machines/", new_name, ".raw");
|
||||
|
||||
r = copy_file_atomic(i->path, new_path, read_only ? 0444 : 0644, false, FS_NOCOW_FL);
|
||||
r = copy_file_atomic(i->path, new_path, read_only ? 0444 : 0644, FS_NOCOW_FL, COPY_REFLINK);
|
||||
break;
|
||||
|
||||
default:
|
||||
|
||||
+1
-1
@@ -44,7 +44,7 @@ static pid_t pager_pid = 0;
|
||||
noreturn static void pager_fallback(void) {
|
||||
int r;
|
||||
|
||||
r = copy_bytes(STDIN_FILENO, STDOUT_FILENO, (uint64_t) -1, false);
|
||||
r = copy_bytes(STDIN_FILENO, STDOUT_FILENO, (uint64_t) -1, 0);
|
||||
if (r < 0) {
|
||||
log_error_errno(r, "Internal pager failed: %m");
|
||||
_exit(EXIT_FAILURE);
|
||||
|
||||
@@ -5300,7 +5300,7 @@ static int cat_file(const char *filename, bool newline) {
|
||||
ansi_normal());
|
||||
fflush(stdout);
|
||||
|
||||
return copy_bytes(fd, STDOUT_FILENO, (uint64_t) -1, false);
|
||||
return copy_bytes(fd, STDOUT_FILENO, (uint64_t) -1, 0);
|
||||
}
|
||||
|
||||
static int cat(int argc, char *argv[], void *userdata) {
|
||||
@@ -6582,7 +6582,7 @@ static int create_edit_temp_file(const char *new_path, const char *original_path
|
||||
if (r < 0)
|
||||
return log_error_errno(r, "Failed to create directories for \"%s\": %m", new_path);
|
||||
|
||||
r = copy_file(original_path, t, 0, 0644, 0);
|
||||
r = copy_file(original_path, t, 0, 0644, 0, COPY_REFLINK);
|
||||
if (r == -ENOENT) {
|
||||
|
||||
r = touch(t);
|
||||
|
||||
@@ -211,7 +211,7 @@ static int make_backup(const char *target, const char *x) {
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
r = copy_bytes(src, fileno(dst), (uint64_t) -1, true);
|
||||
r = copy_bytes(src, fileno(dst), (uint64_t) -1, COPY_REFLINK);
|
||||
if (r < 0)
|
||||
goto fail;
|
||||
|
||||
|
||||
+13
-12
@@ -31,6 +31,7 @@
|
||||
#include "rm-rf.h"
|
||||
#include "string-util.h"
|
||||
#include "strv.h"
|
||||
#include "user-util.h"
|
||||
#include "util.h"
|
||||
|
||||
static void test_copy_file(void) {
|
||||
@@ -52,7 +53,7 @@ static void test_copy_file(void) {
|
||||
|
||||
assert_se(write_string_file(fn, "foo bar bar bar foo", WRITE_STRING_FILE_CREATE) == 0);
|
||||
|
||||
assert_se(copy_file(fn, fn_copy, 0, 0644, 0) == 0);
|
||||
assert_se(copy_file(fn, fn_copy, 0, 0644, 0, COPY_REFLINK) == 0);
|
||||
|
||||
assert_se(read_full_file(fn_copy, &buf, &sz) == 0);
|
||||
assert_se(streq(buf, "foo bar bar bar foo\n"));
|
||||
@@ -77,8 +78,8 @@ static void test_copy_file_fd(void) {
|
||||
assert_se(out_fd >= 0);
|
||||
|
||||
assert_se(write_string_file(in_fn, text, WRITE_STRING_FILE_CREATE) == 0);
|
||||
assert_se(copy_file_fd("/a/file/which/does/not/exist/i/guess", out_fd, true) < 0);
|
||||
assert_se(copy_file_fd(in_fn, out_fd, true) >= 0);
|
||||
assert_se(copy_file_fd("/a/file/which/does/not/exist/i/guess", out_fd, COPY_REFLINK) < 0);
|
||||
assert_se(copy_file_fd(in_fn, out_fd, COPY_REFLINK) >= 0);
|
||||
assert_se(lseek(out_fd, SEEK_SET, 0) == 0);
|
||||
|
||||
assert_se(read(out_fd, buf, sizeof(buf)) == sizeof(text) - 1);
|
||||
@@ -125,7 +126,7 @@ static void test_copy_tree(void) {
|
||||
unixsockp = strjoina(original_dir, "unixsock");
|
||||
assert_se(mknod(unixsockp, S_IFSOCK|0644, 0) >= 0);
|
||||
|
||||
assert_se(copy_tree(original_dir, copy_dir, true) == 0);
|
||||
assert_se(copy_tree(original_dir, copy_dir, UID_INVALID, GID_INVALID, COPY_REFLINK|COPY_MERGE) == 0);
|
||||
|
||||
STRV_FOREACH(p, files) {
|
||||
_cleanup_free_ char *buf = NULL, *f;
|
||||
@@ -152,8 +153,8 @@ static void test_copy_tree(void) {
|
||||
assert_se(stat(unixsockp, &st) >= 0);
|
||||
assert_se(S_ISSOCK(st.st_mode));
|
||||
|
||||
assert_se(copy_tree(original_dir, copy_dir, false) < 0);
|
||||
assert_se(copy_tree("/tmp/inexistent/foo/bar/fsdoi", copy_dir, false) < 0);
|
||||
assert_se(copy_tree(original_dir, copy_dir, UID_INVALID, GID_INVALID, COPY_REFLINK) < 0);
|
||||
assert_se(copy_tree("/tmp/inexistent/foo/bar/fsdoi", copy_dir, UID_INVALID, GID_INVALID, COPY_REFLINK) < 0);
|
||||
|
||||
(void) rm_rf(copy_dir, REMOVE_ROOT|REMOVE_PHYSICAL);
|
||||
(void) rm_rf(original_dir, REMOVE_ROOT|REMOVE_PHYSICAL);
|
||||
@@ -172,7 +173,7 @@ static void test_copy_bytes(void) {
|
||||
|
||||
assert_se(pipe2(pipefd, O_CLOEXEC) == 0);
|
||||
|
||||
r = copy_bytes(infd, pipefd[1], (uint64_t) -1, false);
|
||||
r = copy_bytes(infd, pipefd[1], (uint64_t) -1, 0);
|
||||
assert_se(r == 0);
|
||||
|
||||
r = read(pipefd[0], buf, sizeof(buf));
|
||||
@@ -185,13 +186,13 @@ static void test_copy_bytes(void) {
|
||||
assert_se(strneq(buf, buf2, r));
|
||||
|
||||
/* test copy_bytes with invalid descriptors */
|
||||
r = copy_bytes(pipefd[0], pipefd[0], 1, false);
|
||||
r = copy_bytes(pipefd[0], pipefd[0], 1, 0);
|
||||
assert_se(r == -EBADF);
|
||||
|
||||
r = copy_bytes(pipefd[1], pipefd[1], 1, false);
|
||||
r = copy_bytes(pipefd[1], pipefd[1], 1, 0);
|
||||
assert_se(r == -EBADF);
|
||||
|
||||
r = copy_bytes(pipefd[1], infd, 1, false);
|
||||
r = copy_bytes(pipefd[1], infd, 1, 0);
|
||||
assert_se(r == -EBADF);
|
||||
}
|
||||
|
||||
@@ -213,7 +214,7 @@ static void test_copy_bytes_regular_file(const char *src, bool try_reflink, uint
|
||||
fd3 = mkostemp_safe(fn3);
|
||||
assert_se(fd3 >= 0);
|
||||
|
||||
r = copy_bytes(fd, fd2, max_bytes, try_reflink);
|
||||
r = copy_bytes(fd, fd2, max_bytes, try_reflink ? COPY_REFLINK : 0);
|
||||
if (max_bytes == (uint64_t) -1)
|
||||
assert_se(r == 0);
|
||||
else
|
||||
@@ -221,7 +222,7 @@ static void test_copy_bytes_regular_file(const char *src, bool try_reflink, uint
|
||||
|
||||
assert_se(lseek(fd2, 0, SEEK_SET) == 0);
|
||||
|
||||
r = copy_bytes(fd2, fd3, max_bytes, try_reflink);
|
||||
r = copy_bytes(fd2, fd3, max_bytes, try_reflink ? COPY_REFLINK : 0);
|
||||
if (max_bytes == (uint64_t) -1)
|
||||
assert_se(r == 0);
|
||||
else
|
||||
|
||||
@@ -1170,7 +1170,7 @@ static int create_item(Item *i) {
|
||||
return log_error_errno(r, "Failed to substitute specifiers in copy source %s: %m", i->argument);
|
||||
|
||||
log_debug("Copying tree \"%s\" to \"%s\".", resolved, i->path);
|
||||
r = copy_tree(resolved, i->path, false);
|
||||
r = copy_tree(resolved, i->path, i->uid_set ? i->uid : UID_INVALID, i->gid_set ? i->gid : GID_INVALID, COPY_REFLINK);
|
||||
|
||||
if (r == -EROFS && stat(i->path, &st) == 0)
|
||||
r = -EEXIST;
|
||||
|
||||
Reference in New Issue
Block a user