mirror of
https://github.com/systemd/systemd
synced 2026-03-24 15:55:00 +01:00
Compare commits
No commits in common. "b10abe4bba61aebe4c667c412741193f11886298" and "b98855d90be454cfe66e43fa611e8433b21d124d" have entirely different histories.
b10abe4bba
...
b98855d90b
@ -722,8 +722,6 @@ if time_epoch == -1
|
|||||||
endif
|
endif
|
||||||
conf.set('TIME_EPOCH', time_epoch)
|
conf.set('TIME_EPOCH', time_epoch)
|
||||||
|
|
||||||
conf.set('CLOCK_VALID_RANGE_USEC_MAX', get_option('clock-valid-range-usec-max'))
|
|
||||||
|
|
||||||
foreach tuple : [['system-alloc-uid-min', 'SYS_UID_MIN', 1], # Also see login.defs(5).
|
foreach tuple : [['system-alloc-uid-min', 'SYS_UID_MIN', 1], # Also see login.defs(5).
|
||||||
['system-uid-max', 'SYS_UID_MAX', 999],
|
['system-uid-max', 'SYS_UID_MAX', 999],
|
||||||
['system-alloc-gid-min', 'SYS_GID_MIN', 1],
|
['system-alloc-gid-min', 'SYS_GID_MIN', 1],
|
||||||
|
|||||||
@ -208,8 +208,6 @@ option('status-unit-format-default', type : 'combo',
|
|||||||
description : 'use unit name or description in messages by default')
|
description : 'use unit name or description in messages by default')
|
||||||
option('time-epoch', type : 'integer', value : '-1',
|
option('time-epoch', type : 'integer', value : '-1',
|
||||||
description : 'time epoch for time clients')
|
description : 'time epoch for time clients')
|
||||||
option('clock-valid-range-usec-max', type : 'integer', value : '473364000000000', # 15 years
|
|
||||||
description : 'maximum value in microseconds for the difference between RTC and epoch, exceeding which is considered an RTC error')
|
|
||||||
|
|
||||||
option('system-alloc-uid-min', type : 'integer', value : '-1',
|
option('system-alloc-uid-min', type : 'integer', value : '-1',
|
||||||
description : 'minimum system UID used when allocating')
|
description : 'minimum system UID used when allocating')
|
||||||
|
|||||||
@ -2,11 +2,11 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include <dirent.h>
|
#include <dirent.h>
|
||||||
#include <fcntl.h>
|
|
||||||
#include <stdbool.h>
|
#include <stdbool.h>
|
||||||
#include <stddef.h>
|
#include <stddef.h>
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
#include <sys/stat.h>
|
#include <sys/stat.h>
|
||||||
|
#include <sys/fcntl.h>
|
||||||
#include <sys/types.h>
|
#include <sys/types.h>
|
||||||
|
|
||||||
#include "macro.h"
|
#include "macro.h"
|
||||||
|
|||||||
@ -83,7 +83,6 @@
|
|||||||
#include "switch-root.h"
|
#include "switch-root.h"
|
||||||
#include "sysctl-util.h"
|
#include "sysctl-util.h"
|
||||||
#include "terminal-util.h"
|
#include "terminal-util.h"
|
||||||
#include "time-util.h"
|
|
||||||
#include "umask-util.h"
|
#include "umask-util.h"
|
||||||
#include "user-util.h"
|
#include "user-util.h"
|
||||||
#include "util.h"
|
#include "util.h"
|
||||||
@ -1599,18 +1598,11 @@ static void initialize_clock(void) {
|
|||||||
*/
|
*/
|
||||||
(void) clock_reset_timewarp();
|
(void) clock_reset_timewarp();
|
||||||
|
|
||||||
ClockChangeDirection change_dir;
|
r = clock_apply_epoch();
|
||||||
r = clock_apply_epoch(&change_dir);
|
if (r < 0)
|
||||||
if (r > 0 && change_dir == CLOCK_CHANGE_FORWARD)
|
|
||||||
log_info("System time before build time, advancing clock.");
|
|
||||||
else if (r > 0 && change_dir == CLOCK_CHANGE_BACKWARD)
|
|
||||||
log_info("System time is further ahead than %s after build time, resetting clock to build time.",
|
|
||||||
FORMAT_TIMESPAN(CLOCK_VALID_RANGE_USEC_MAX, USEC_PER_DAY));
|
|
||||||
else if (r < 0 && change_dir == CLOCK_CHANGE_FORWARD)
|
|
||||||
log_error_errno(r, "Current system time is before build time, but cannot correct: %m");
|
log_error_errno(r, "Current system time is before build time, but cannot correct: %m");
|
||||||
else if (r < 0 && change_dir == CLOCK_CHANGE_BACKWARD)
|
else if (r > 0)
|
||||||
log_error_errno(r, "Current system time is further ahead %s after build time, but cannot correct: %m",
|
log_info("System time before build time, advancing clock.");
|
||||||
FORMAT_TIMESPAN(CLOCK_VALID_RANGE_USEC_MAX, USEC_PER_DAY));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static void apply_clock_update(void) {
|
static void apply_clock_update(void) {
|
||||||
|
|||||||
@ -297,7 +297,7 @@ static int group_lookup_name(Manager *m, const char *name, gid_t *ret_gid, char
|
|||||||
desc = mfree(desc);
|
desc = mfree(desc);
|
||||||
|
|
||||||
*ret_gid = converted_gid;
|
*ret_gid = converted_gid;
|
||||||
*ret_description = TAKE_PTR(desc);
|
*ret_description = desc;
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -1613,7 +1613,7 @@ int btrfs_subvol_snapshot_fd_full(
|
|||||||
return -EISDIR;
|
return -EISDIR;
|
||||||
|
|
||||||
r = btrfs_subvol_make(new_path);
|
r = btrfs_subvol_make(new_path);
|
||||||
if (ERRNO_IS_NOT_SUPPORTED(r) && (flags & BTRFS_SNAPSHOT_FALLBACK_DIRECTORY)) {
|
if (r == -ENOTTY && (flags & BTRFS_SNAPSHOT_FALLBACK_DIRECTORY)) {
|
||||||
/* If the destination doesn't support subvolumes, then use a plain directory, if that's requested. */
|
/* If the destination doesn't support subvolumes, then use a plain directory, if that's requested. */
|
||||||
if (mkdir(new_path, 0755) < 0)
|
if (mkdir(new_path, 0755) < 0)
|
||||||
return -errno;
|
return -errno;
|
||||||
@ -1624,15 +1624,8 @@ int btrfs_subvol_snapshot_fd_full(
|
|||||||
|
|
||||||
r = copy_directory_fd_full(
|
r = copy_directory_fd_full(
|
||||||
old_fd, new_path,
|
old_fd, new_path,
|
||||||
COPY_MERGE_EMPTY|
|
COPY_MERGE|COPY_REFLINK|COPY_SAME_MOUNT|COPY_HARDLINKS|(FLAGS_SET(flags, BTRFS_SNAPSHOT_SIGINT) ? COPY_SIGINT : 0),
|
||||||
COPY_REFLINK|
|
progress_path, progress_bytes, userdata);
|
||||||
COPY_SAME_MOUNT|
|
|
||||||
COPY_HARDLINKS|
|
|
||||||
(FLAGS_SET(flags, BTRFS_SNAPSHOT_SIGINT) ? COPY_SIGINT : 0)|
|
|
||||||
(FLAGS_SET(flags, BTRFS_SNAPSHOT_SIGTERM) ? COPY_SIGTERM : 0),
|
|
||||||
progress_path,
|
|
||||||
progress_bytes,
|
|
||||||
userdata);
|
|
||||||
if (r < 0)
|
if (r < 0)
|
||||||
goto fallback_fail;
|
goto fallback_fail;
|
||||||
|
|
||||||
|
|||||||
@ -35,7 +35,6 @@ typedef enum BtrfsSnapshotFlags {
|
|||||||
BTRFS_SNAPSHOT_FALLBACK_DIRECTORY = 1 << 4, /* If the destination doesn't support subvolumes, reflink/copy instead */
|
BTRFS_SNAPSHOT_FALLBACK_DIRECTORY = 1 << 4, /* If the destination doesn't support subvolumes, reflink/copy instead */
|
||||||
BTRFS_SNAPSHOT_FALLBACK_IMMUTABLE = 1 << 5, /* When we can't create a subvolume, use the FS_IMMUTABLE attribute for indicating read-only */
|
BTRFS_SNAPSHOT_FALLBACK_IMMUTABLE = 1 << 5, /* When we can't create a subvolume, use the FS_IMMUTABLE attribute for indicating read-only */
|
||||||
BTRFS_SNAPSHOT_SIGINT = 1 << 6, /* Check for SIGINT regularly, and return EINTR if seen */
|
BTRFS_SNAPSHOT_SIGINT = 1 << 6, /* Check for SIGINT regularly, and return EINTR if seen */
|
||||||
BTRFS_SNAPSHOT_SIGTERM = 1 << 7, /* Ditto, but for SIGTERM */
|
|
||||||
} BtrfsSnapshotFlags;
|
} BtrfsSnapshotFlags;
|
||||||
|
|
||||||
typedef enum BtrfsRemoveFlags {
|
typedef enum BtrfsRemoveFlags {
|
||||||
|
|||||||
@ -139,15 +139,10 @@ int clock_reset_timewarp(void) {
|
|||||||
|
|
||||||
#define EPOCH_FILE "/usr/lib/clock-epoch"
|
#define EPOCH_FILE "/usr/lib/clock-epoch"
|
||||||
|
|
||||||
int clock_apply_epoch(ClockChangeDirection *ret_attempted_change) {
|
int clock_apply_epoch(void) {
|
||||||
struct stat st;
|
struct stat st;
|
||||||
struct timespec ts;
|
struct timespec ts;
|
||||||
usec_t epoch_usec, now_usec;
|
usec_t epoch_usec;
|
||||||
|
|
||||||
/* NB: we update *ret_attempted_change in *all* cases, both
|
|
||||||
* on success and failure, to indicate what we intended to do! */
|
|
||||||
|
|
||||||
assert(ret_attempted_change);
|
|
||||||
|
|
||||||
if (stat(EPOCH_FILE, &st) < 0) {
|
if (stat(EPOCH_FILE, &st) < 0) {
|
||||||
if (errno != ENOENT)
|
if (errno != ENOENT)
|
||||||
@ -157,15 +152,8 @@ int clock_apply_epoch(ClockChangeDirection *ret_attempted_change) {
|
|||||||
} else
|
} else
|
||||||
epoch_usec = timespec_load(&st.st_mtim);
|
epoch_usec = timespec_load(&st.st_mtim);
|
||||||
|
|
||||||
now_usec = now(CLOCK_REALTIME);
|
if (now(CLOCK_REALTIME) >= epoch_usec)
|
||||||
if (now_usec < epoch_usec)
|
|
||||||
*ret_attempted_change = CLOCK_CHANGE_FORWARD;
|
|
||||||
else if (now_usec > usec_add(epoch_usec, CLOCK_VALID_RANGE_USEC_MAX))
|
|
||||||
*ret_attempted_change = CLOCK_CHANGE_BACKWARD;
|
|
||||||
else {
|
|
||||||
*ret_attempted_change = CLOCK_CHANGE_NOOP;
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
|
||||||
|
|
||||||
if (clock_settime(CLOCK_REALTIME, timespec_store(&ts, epoch_usec)) < 0)
|
if (clock_settime(CLOCK_REALTIME, timespec_store(&ts, epoch_usec)) < 0)
|
||||||
return -errno;
|
return -errno;
|
||||||
|
|||||||
@ -1,20 +1,11 @@
|
|||||||
/* SPDX-License-Identifier: LGPL-2.1-or-later */
|
/* SPDX-License-Identifier: LGPL-2.1-or-later */
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include <errno.h>
|
|
||||||
#include <time.h>
|
#include <time.h>
|
||||||
|
|
||||||
typedef enum ClockChangeDirection {
|
|
||||||
CLOCK_CHANGE_NOOP,
|
|
||||||
CLOCK_CHANGE_FORWARD,
|
|
||||||
CLOCK_CHANGE_BACKWARD,
|
|
||||||
_CLOCK_CHANGE_MAX,
|
|
||||||
_CLOCK_CHANGE_INVALID = -EINVAL,
|
|
||||||
} ClockChangeDirection;
|
|
||||||
|
|
||||||
int clock_is_localtime(const char* adjtime_path);
|
int clock_is_localtime(const char* adjtime_path);
|
||||||
int clock_set_timezone(int *ret_minutesdelta);
|
int clock_set_timezone(int *ret_minutesdelta);
|
||||||
int clock_reset_timewarp(void);
|
int clock_reset_timewarp(void);
|
||||||
int clock_get_hwclock(struct tm *tm);
|
int clock_get_hwclock(struct tm *tm);
|
||||||
int clock_set_hwclock(const struct tm *tm);
|
int clock_set_hwclock(const struct tm *tm);
|
||||||
int clock_apply_epoch(ClockChangeDirection *ret_attempted_change);
|
int clock_apply_epoch(void);
|
||||||
|
|||||||
@ -88,23 +88,6 @@ static int fd_is_nonblock_pipe(int fd) {
|
|||||||
return FLAGS_SET(flags, O_NONBLOCK) ? FD_IS_NONBLOCKING_PIPE : FD_IS_BLOCKING_PIPE;
|
return FLAGS_SET(flags, O_NONBLOCK) ? FD_IS_NONBLOCKING_PIPE : FD_IS_BLOCKING_PIPE;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int look_for_signals(CopyFlags copy_flags) {
|
|
||||||
int r;
|
|
||||||
|
|
||||||
if ((copy_flags & (COPY_SIGINT|COPY_SIGTERM)) == 0)
|
|
||||||
return 0;
|
|
||||||
|
|
||||||
r = pop_pending_signal(copy_flags & COPY_SIGINT ? SIGINT : 0,
|
|
||||||
copy_flags & COPY_SIGTERM ? SIGTERM : 0);
|
|
||||||
if (r < 0)
|
|
||||||
return r;
|
|
||||||
if (r != 0)
|
|
||||||
return log_debug_errno(SYNTHETIC_ERRNO(EINTR),
|
|
||||||
"Got %s, cancelling copy operation.", signal_to_string(r));
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
int copy_bytes_full(
|
int copy_bytes_full(
|
||||||
int fdf, int fdt,
|
int fdf, int fdt,
|
||||||
uint64_t max_bytes,
|
uint64_t max_bytes,
|
||||||
@ -193,9 +176,13 @@ int copy_bytes_full(
|
|||||||
if (max_bytes <= 0)
|
if (max_bytes <= 0)
|
||||||
return 1; /* return > 0 if we hit the max_bytes limit */
|
return 1; /* return > 0 if we hit the max_bytes limit */
|
||||||
|
|
||||||
r = look_for_signals(copy_flags);
|
if (FLAGS_SET(copy_flags, COPY_SIGINT)) {
|
||||||
|
r = pop_pending_signal(SIGINT);
|
||||||
if (r < 0)
|
if (r < 0)
|
||||||
return r;
|
return r;
|
||||||
|
if (r > 0)
|
||||||
|
return -EINTR;
|
||||||
|
}
|
||||||
|
|
||||||
if (max_bytes != UINT64_MAX && m > max_bytes)
|
if (max_bytes != UINT64_MAX && m > max_bytes)
|
||||||
m = max_bytes;
|
m = max_bytes;
|
||||||
@ -640,8 +627,10 @@ static int fd_copy_regular(
|
|||||||
return -errno;
|
return -errno;
|
||||||
|
|
||||||
r = copy_bytes_full(fdf, fdt, UINT64_MAX, copy_flags, NULL, NULL, progress, userdata);
|
r = copy_bytes_full(fdf, fdt, UINT64_MAX, copy_flags, NULL, NULL, progress, userdata);
|
||||||
if (r < 0)
|
if (r < 0) {
|
||||||
goto fail;
|
(void) unlinkat(dt, to, 0);
|
||||||
|
return r;
|
||||||
|
}
|
||||||
|
|
||||||
if (fchown(fdt,
|
if (fchown(fdt,
|
||||||
uid_is_valid(override_uid) ? override_uid : st->st_uid,
|
uid_is_valid(override_uid) ? override_uid : st->st_uid,
|
||||||
@ -654,25 +643,16 @@ static int fd_copy_regular(
|
|||||||
(void) futimens(fdt, (struct timespec[]) { st->st_atim, st->st_mtim });
|
(void) futimens(fdt, (struct timespec[]) { st->st_atim, st->st_mtim });
|
||||||
(void) copy_xattr(fdf, fdt);
|
(void) copy_xattr(fdf, fdt);
|
||||||
|
|
||||||
if (copy_flags & COPY_FSYNC) {
|
q = close(fdt);
|
||||||
if (fsync(fdt) < 0) {
|
fdt = -1;
|
||||||
r = -errno;
|
|
||||||
goto fail;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
q = close_nointr(TAKE_FD(fdt)); /* even if this fails, the fd is now invalidated */
|
|
||||||
if (q < 0) {
|
if (q < 0) {
|
||||||
r = q;
|
r = -errno;
|
||||||
goto fail;
|
(void) unlinkat(dt, to, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
(void) memorize_hardlink(hardlink_context, st, dt, to);
|
(void) memorize_hardlink(hardlink_context, st, dt, to);
|
||||||
return r;
|
return r;
|
||||||
|
|
||||||
fail:
|
|
||||||
(void) unlinkat(dt, to, 0);
|
|
||||||
return r;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static int fd_copy_fifo(
|
static int fd_copy_fifo(
|
||||||
@ -865,9 +845,13 @@ static int fd_copy_directory(
|
|||||||
if (dot_or_dot_dot(de->d_name))
|
if (dot_or_dot_dot(de->d_name))
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
r = look_for_signals(copy_flags);
|
if (FLAGS_SET(copy_flags, COPY_SIGINT)) {
|
||||||
|
r = pop_pending_signal(SIGINT);
|
||||||
if (r < 0)
|
if (r < 0)
|
||||||
return r;
|
return r;
|
||||||
|
if (r > 0)
|
||||||
|
return -EINTR;
|
||||||
|
}
|
||||||
|
|
||||||
if (fstatat(dirfd(d), de->d_name, &buf, AT_SYMLINK_NOFOLLOW) < 0) {
|
if (fstatat(dirfd(d), de->d_name, &buf, AT_SYMLINK_NOFOLLOW) < 0) {
|
||||||
r = -errno;
|
r = -errno;
|
||||||
@ -928,7 +912,7 @@ static int fd_copy_directory(
|
|||||||
else
|
else
|
||||||
q = -EOPNOTSUPP;
|
q = -EOPNOTSUPP;
|
||||||
|
|
||||||
if (q == -EINTR) /* Propagate SIGINT/SIGTERM up instantly */
|
if (q == -EINTR) /* Propagate SIGINT up instantly */
|
||||||
return q;
|
return q;
|
||||||
if (q == -EEXIST && (copy_flags & COPY_MERGE))
|
if (q == -EEXIST && (copy_flags & COPY_MERGE))
|
||||||
q = 0;
|
q = 0;
|
||||||
@ -949,11 +933,6 @@ static int fd_copy_directory(
|
|||||||
(void) futimens(fdt, (struct timespec[]) { st->st_atim, st->st_mtim });
|
(void) futimens(fdt, (struct timespec[]) { st->st_atim, st->st_mtim });
|
||||||
}
|
}
|
||||||
|
|
||||||
if (copy_flags & COPY_FSYNC_FULL) {
|
|
||||||
if (fsync(fdt) < 0)
|
|
||||||
return -errno;
|
|
||||||
}
|
|
||||||
|
|
||||||
return r;
|
return r;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -970,7 +949,6 @@ int copy_tree_at_full(
|
|||||||
void *userdata) {
|
void *userdata) {
|
||||||
|
|
||||||
struct stat st;
|
struct stat st;
|
||||||
int r;
|
|
||||||
|
|
||||||
assert(from);
|
assert(from);
|
||||||
assert(to);
|
assert(to);
|
||||||
@ -979,47 +957,17 @@ int copy_tree_at_full(
|
|||||||
return -errno;
|
return -errno;
|
||||||
|
|
||||||
if (S_ISREG(st.st_mode))
|
if (S_ISREG(st.st_mode))
|
||||||
r = fd_copy_regular(fdf, from, &st, fdt, to, override_uid, override_gid, copy_flags, NULL, progress_bytes, userdata);
|
return fd_copy_regular(fdf, from, &st, fdt, to, override_uid, override_gid, copy_flags, NULL, progress_bytes, userdata);
|
||||||
else if (S_ISDIR(st.st_mode))
|
else if (S_ISDIR(st.st_mode))
|
||||||
r = fd_copy_directory(fdf, from, &st, fdt, to, st.st_dev, COPY_DEPTH_MAX, override_uid, override_gid, copy_flags, NULL, NULL, progress_path, progress_bytes, userdata);
|
return fd_copy_directory(fdf, from, &st, fdt, to, st.st_dev, COPY_DEPTH_MAX, override_uid, override_gid, copy_flags, NULL, NULL, progress_path, progress_bytes, userdata);
|
||||||
else if (S_ISLNK(st.st_mode))
|
else if (S_ISLNK(st.st_mode))
|
||||||
r = fd_copy_symlink(fdf, from, &st, fdt, to, override_uid, override_gid, copy_flags);
|
return fd_copy_symlink(fdf, from, &st, fdt, to, override_uid, override_gid, copy_flags);
|
||||||
else if (S_ISFIFO(st.st_mode))
|
else if (S_ISFIFO(st.st_mode))
|
||||||
r = fd_copy_fifo(fdf, from, &st, fdt, to, override_uid, override_gid, copy_flags, NULL);
|
return fd_copy_fifo(fdf, from, &st, fdt, to, override_uid, override_gid, copy_flags, NULL);
|
||||||
else if (S_ISBLK(st.st_mode) || S_ISCHR(st.st_mode) || S_ISSOCK(st.st_mode))
|
else if (S_ISBLK(st.st_mode) || S_ISCHR(st.st_mode) || S_ISSOCK(st.st_mode))
|
||||||
r = fd_copy_node(fdf, from, &st, fdt, to, override_uid, override_gid, copy_flags, NULL);
|
return fd_copy_node(fdf, from, &st, fdt, to, override_uid, override_gid, copy_flags, NULL);
|
||||||
else
|
else
|
||||||
return -EOPNOTSUPP;
|
return -EOPNOTSUPP;
|
||||||
if (r < 0)
|
|
||||||
return r;
|
|
||||||
|
|
||||||
if (S_ISDIR(st.st_mode) && (copy_flags & COPY_SYNCFS)) {
|
|
||||||
/* If the top-level inode is a directory run syncfs() now. */
|
|
||||||
r = syncfs_path(fdt, to);
|
|
||||||
if (r < 0)
|
|
||||||
return r;
|
|
||||||
} else if ((copy_flags & (COPY_FSYNC_FULL|COPY_SYNCFS)) != 0) {
|
|
||||||
/* fsync() the parent dir of what we just copied if COPY_FSYNC_FULL is set. Also do this in
|
|
||||||
* case COPY_SYNCFS is set but the top-level inode wasn't actually a directory. We do this so that
|
|
||||||
* COPY_SYNCFS provides reasonable synchronization semantics on any kind of inode: when the
|
|
||||||
* copy operation is done the whole inode — regardless of its type — and all its children
|
|
||||||
* will be synchronized to disk. */
|
|
||||||
r = fsync_parent_at(fdt, to);
|
|
||||||
if (r < 0)
|
|
||||||
return r;
|
|
||||||
}
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
static int sync_dir_by_flags(const char *path, CopyFlags copy_flags) {
|
|
||||||
|
|
||||||
if (copy_flags & COPY_SYNCFS)
|
|
||||||
return syncfs_path(AT_FDCWD, path);
|
|
||||||
if (copy_flags & COPY_FSYNC_FULL)
|
|
||||||
return fsync_parent_at(AT_FDCWD, path);
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
int copy_directory_fd_full(
|
int copy_directory_fd_full(
|
||||||
@ -1043,26 +991,7 @@ int copy_directory_fd_full(
|
|||||||
if (r < 0)
|
if (r < 0)
|
||||||
return r;
|
return r;
|
||||||
|
|
||||||
r = fd_copy_directory(
|
return fd_copy_directory(dirfd, NULL, &st, AT_FDCWD, to, st.st_dev, COPY_DEPTH_MAX, UID_INVALID, GID_INVALID, copy_flags, NULL, NULL, progress_path, progress_bytes, userdata);
|
||||||
dirfd, NULL,
|
|
||||||
&st,
|
|
||||||
AT_FDCWD, to,
|
|
||||||
st.st_dev,
|
|
||||||
COPY_DEPTH_MAX,
|
|
||||||
UID_INVALID, GID_INVALID,
|
|
||||||
copy_flags,
|
|
||||||
NULL, NULL,
|
|
||||||
progress_path,
|
|
||||||
progress_bytes,
|
|
||||||
userdata);
|
|
||||||
if (r < 0)
|
|
||||||
return r;
|
|
||||||
|
|
||||||
r = sync_dir_by_flags(to, copy_flags);
|
|
||||||
if (r < 0)
|
|
||||||
return r;
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
int copy_directory_full(
|
int copy_directory_full(
|
||||||
@ -1086,26 +1015,7 @@ int copy_directory_full(
|
|||||||
if (r < 0)
|
if (r < 0)
|
||||||
return r;
|
return r;
|
||||||
|
|
||||||
r = fd_copy_directory(
|
return fd_copy_directory(AT_FDCWD, from, &st, AT_FDCWD, to, st.st_dev, COPY_DEPTH_MAX, UID_INVALID, GID_INVALID, copy_flags, NULL, NULL, progress_path, progress_bytes, userdata);
|
||||||
AT_FDCWD, from,
|
|
||||||
&st,
|
|
||||||
AT_FDCWD, to,
|
|
||||||
st.st_dev,
|
|
||||||
COPY_DEPTH_MAX,
|
|
||||||
UID_INVALID, GID_INVALID,
|
|
||||||
copy_flags,
|
|
||||||
NULL, NULL,
|
|
||||||
progress_path,
|
|
||||||
progress_bytes,
|
|
||||||
userdata);
|
|
||||||
if (r < 0)
|
|
||||||
return r;
|
|
||||||
|
|
||||||
r = sync_dir_by_flags(to, copy_flags);
|
|
||||||
if (r < 0)
|
|
||||||
return r;
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
int copy_file_fd_full(
|
int copy_file_fd_full(
|
||||||
@ -1116,7 +1026,6 @@ int copy_file_fd_full(
|
|||||||
void *userdata) {
|
void *userdata) {
|
||||||
|
|
||||||
_cleanup_close_ int fdf = -1;
|
_cleanup_close_ int fdf = -1;
|
||||||
struct stat st;
|
|
||||||
int r;
|
int r;
|
||||||
|
|
||||||
assert(from);
|
assert(from);
|
||||||
@ -1126,32 +1035,12 @@ int copy_file_fd_full(
|
|||||||
if (fdf < 0)
|
if (fdf < 0)
|
||||||
return -errno;
|
return -errno;
|
||||||
|
|
||||||
r = fd_verify_regular(fdf);
|
|
||||||
if (r < 0)
|
|
||||||
return r;
|
|
||||||
|
|
||||||
if (fstat(fdt, &st) < 0)
|
|
||||||
return -errno;
|
|
||||||
|
|
||||||
r = copy_bytes_full(fdf, fdt, UINT64_MAX, copy_flags, NULL, NULL, progress_bytes, userdata);
|
r = copy_bytes_full(fdf, fdt, UINT64_MAX, copy_flags, NULL, NULL, progress_bytes, userdata);
|
||||||
if (r < 0)
|
|
||||||
return r;
|
|
||||||
|
|
||||||
if (S_ISREG(fdt)) {
|
|
||||||
(void) copy_times(fdf, fdt, copy_flags);
|
(void) copy_times(fdf, fdt, copy_flags);
|
||||||
(void) copy_xattr(fdf, fdt);
|
(void) copy_xattr(fdf, fdt);
|
||||||
}
|
|
||||||
|
|
||||||
if (copy_flags & COPY_FSYNC_FULL) {
|
|
||||||
r = fsync_full(fdt);
|
|
||||||
if (r < 0)
|
|
||||||
return r;
|
return r;
|
||||||
} else if (copy_flags & COPY_FSYNC) {
|
|
||||||
if (fsync(fdt) < 0)
|
|
||||||
return -errno;
|
|
||||||
}
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
int copy_file_full(
|
int copy_file_full(
|
||||||
@ -1165,9 +1054,9 @@ int copy_file_full(
|
|||||||
copy_progress_bytes_t progress_bytes,
|
copy_progress_bytes_t progress_bytes,
|
||||||
void *userdata) {
|
void *userdata) {
|
||||||
|
|
||||||
_cleanup_close_ int fdf = -1, fdt = -1;
|
_cleanup_close_ int fdf = -1;
|
||||||
struct stat st;
|
struct stat st;
|
||||||
int r;
|
int r, fdt = -1; /* avoid false maybe-uninitialized warning */
|
||||||
|
|
||||||
assert(from);
|
assert(from);
|
||||||
assert(to);
|
assert(to);
|
||||||
@ -1176,13 +1065,10 @@ int copy_file_full(
|
|||||||
if (fdf < 0)
|
if (fdf < 0)
|
||||||
return -errno;
|
return -errno;
|
||||||
|
|
||||||
|
if (mode == MODE_INVALID)
|
||||||
if (fstat(fdf, &st) < 0)
|
if (fstat(fdf, &st) < 0)
|
||||||
return -errno;
|
return -errno;
|
||||||
|
|
||||||
r = stat_verify_regular(&st);
|
|
||||||
if (r < 0)
|
|
||||||
return r;
|
|
||||||
|
|
||||||
RUN_WITH_UMASK(0000) {
|
RUN_WITH_UMASK(0000) {
|
||||||
if (copy_flags & COPY_MAC_CREATE) {
|
if (copy_flags & COPY_MAC_CREATE) {
|
||||||
r = mac_selinux_create_file_prepare(to, S_IFREG);
|
r = mac_selinux_create_file_prepare(to, S_IFREG);
|
||||||
@ -1197,18 +1083,15 @@ int copy_file_full(
|
|||||||
return -errno;
|
return -errno;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!FLAGS_SET(flags, O_EXCL)) { /* if O_EXCL was used we created the thing as regular file, no need to check again */
|
|
||||||
r = fd_verify_regular(fdt);
|
|
||||||
if (r < 0)
|
|
||||||
goto fail;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (chattr_mask != 0)
|
if (chattr_mask != 0)
|
||||||
(void) chattr_fd(fdt, chattr_flags, chattr_mask & CHATTR_EARLY_FL, NULL);
|
(void) chattr_fd(fdt, chattr_flags, chattr_mask & CHATTR_EARLY_FL, NULL);
|
||||||
|
|
||||||
r = copy_bytes_full(fdf, fdt, UINT64_MAX, copy_flags, NULL, NULL, progress_bytes, userdata);
|
r = copy_bytes_full(fdf, fdt, UINT64_MAX, copy_flags, NULL, NULL, progress_bytes, userdata);
|
||||||
if (r < 0)
|
if (r < 0) {
|
||||||
goto fail;
|
close(fdt);
|
||||||
|
(void) unlink(to);
|
||||||
|
return r;
|
||||||
|
}
|
||||||
|
|
||||||
(void) copy_times(fdf, fdt, copy_flags);
|
(void) copy_times(fdf, fdt, copy_flags);
|
||||||
(void) copy_xattr(fdf, fdt);
|
(void) copy_xattr(fdf, fdt);
|
||||||
@ -1216,31 +1099,12 @@ int copy_file_full(
|
|||||||
if (chattr_mask != 0)
|
if (chattr_mask != 0)
|
||||||
(void) chattr_fd(fdt, chattr_flags, chattr_mask & ~CHATTR_EARLY_FL, NULL);
|
(void) chattr_fd(fdt, chattr_flags, chattr_mask & ~CHATTR_EARLY_FL, NULL);
|
||||||
|
|
||||||
if (copy_flags & (COPY_FSYNC|COPY_FSYNC_FULL)) {
|
if (close(fdt) < 0) {
|
||||||
if (fsync(fdt) < 0) {
|
unlink_noerrno(to);
|
||||||
r = -errno;
|
return -errno;
|
||||||
goto fail;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
r = close_nointr(TAKE_FD(fdt)); /* even if this fails, the fd is now invalidated */
|
|
||||||
if (r < 0)
|
|
||||||
goto fail;
|
|
||||||
|
|
||||||
if (copy_flags & COPY_FSYNC_FULL) {
|
|
||||||
r = fsync_parent_at(AT_FDCWD, to);
|
|
||||||
if (r < 0)
|
|
||||||
goto fail;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
fail:
|
|
||||||
/* Only unlink if we definitely are the ones who created the file */
|
|
||||||
if (FLAGS_SET(flags, O_EXCL))
|
|
||||||
(void) unlink(to);
|
|
||||||
|
|
||||||
return r;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
int copy_file_atomic_full(
|
int copy_file_atomic_full(
|
||||||
@ -1308,12 +1172,6 @@ int copy_file_atomic_full(
|
|||||||
if (fchmod(fdt, mode) < 0)
|
if (fchmod(fdt, mode) < 0)
|
||||||
return -errno;
|
return -errno;
|
||||||
|
|
||||||
if ((copy_flags & (COPY_FSYNC|COPY_FSYNC_FULL))) {
|
|
||||||
/* Sync the file */
|
|
||||||
if (fsync(fdt) < 0)
|
|
||||||
return -errno;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (copy_flags & COPY_REPLACE) {
|
if (copy_flags & COPY_REPLACE) {
|
||||||
if (renameat(AT_FDCWD, t, AT_FDCWD, to) < 0)
|
if (renameat(AT_FDCWD, t, AT_FDCWD, to) < 0)
|
||||||
return -errno;
|
return -errno;
|
||||||
@ -1323,27 +1181,11 @@ int copy_file_atomic_full(
|
|||||||
return r;
|
return r;
|
||||||
}
|
}
|
||||||
|
|
||||||
t = mfree(t);
|
|
||||||
|
|
||||||
if (chattr_mask != 0)
|
if (chattr_mask != 0)
|
||||||
(void) chattr_fd(fdt, chattr_flags, chattr_mask & ~CHATTR_EARLY_FL, NULL);
|
(void) chattr_fd(fdt, chattr_flags, chattr_mask & ~CHATTR_EARLY_FL, NULL);
|
||||||
|
|
||||||
r = close_nointr(TAKE_FD(fdt)); /* even if this fails, the fd is now invalidated */
|
t = mfree(t);
|
||||||
if (r < 0)
|
|
||||||
goto fail;
|
|
||||||
|
|
||||||
if (copy_flags & COPY_FSYNC_FULL) {
|
|
||||||
/* Sync the parent directory */
|
|
||||||
r = fsync_parent_at(AT_FDCWD, to);
|
|
||||||
if (r < 0)
|
|
||||||
goto fail;
|
|
||||||
}
|
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
fail:
|
|
||||||
(void) unlink(to);
|
|
||||||
return r;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
int copy_times(int fdf, int fdt, CopyFlags flags) {
|
int copy_times(int fdf, int fdt, CopyFlags flags) {
|
||||||
|
|||||||
@ -17,12 +17,8 @@ typedef enum CopyFlags {
|
|||||||
COPY_MERGE_EMPTY = 1 << 4, /* Merge an existing, empty directory with our new tree to copy */
|
COPY_MERGE_EMPTY = 1 << 4, /* Merge an existing, empty directory with our new tree to copy */
|
||||||
COPY_CRTIME = 1 << 5, /* Generate a user.crtime_usec xattr off the source crtime if there is one, on copying */
|
COPY_CRTIME = 1 << 5, /* Generate a user.crtime_usec xattr off the source crtime if there is one, on copying */
|
||||||
COPY_SIGINT = 1 << 6, /* Check for SIGINT regularly and return EINTR if seen (caller needs to block SIGINT) */
|
COPY_SIGINT = 1 << 6, /* Check for SIGINT regularly and return EINTR if seen (caller needs to block SIGINT) */
|
||||||
COPY_SIGTERM = 1 << 7, /* ditto, but for SIGTERM */
|
COPY_MAC_CREATE = 1 << 7, /* Create files with the correct MAC label (currently SELinux only) */
|
||||||
COPY_MAC_CREATE = 1 << 8, /* Create files with the correct MAC label (currently SELinux only) */
|
COPY_HARDLINKS = 1 << 8, /* Try to reproduce hard links */
|
||||||
COPY_HARDLINKS = 1 << 9, /* Try to reproduce hard links */
|
|
||||||
COPY_FSYNC = 1 << 10, /* fsync() after we are done */
|
|
||||||
COPY_FSYNC_FULL = 1 << 11, /* fsync_full() after we are done */
|
|
||||||
COPY_SYNCFS = 1 << 12, /* syncfs() the *top-level* dir after we are done */
|
|
||||||
} CopyFlags;
|
} CopyFlags;
|
||||||
|
|
||||||
typedef int (*copy_progress_bytes_t)(uint64_t n_bytes, void *userdata);
|
typedef int (*copy_progress_bytes_t)(uint64_t n_bytes, void *userdata);
|
||||||
|
|||||||
@ -1,5 +1,5 @@
|
|||||||
/* SPDX-License-Identifier: LGPL-2.1-or-later */
|
/* SPDX-License-Identifier: LGPL-2.1-or-later */
|
||||||
#include <poll.h>
|
#include <sys/poll.h>
|
||||||
|
|
||||||
#include "fd-util.h"
|
#include "fd-util.h"
|
||||||
#include "io-util.h"
|
#include "io-util.h"
|
||||||
|
|||||||
@ -1,7 +1,7 @@
|
|||||||
/* SPDX-License-Identifier: LGPL-2.1-or-later */
|
/* SPDX-License-Identifier: LGPL-2.1-or-later */
|
||||||
|
|
||||||
#include <malloc.h>
|
#include <malloc.h>
|
||||||
#include <poll.h>
|
#include <sys/poll.h>
|
||||||
|
|
||||||
#include "alloc-util.h"
|
#include "alloc-util.h"
|
||||||
#include "errno-util.h"
|
#include "errno-util.h"
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user