From 9d096f42802208d6cb54ab25a2e9cc90925f84c7 Mon Sep 17 00:00:00 2001 From: Jakub Hrozek Date: Fri, 25 Jan 2013 10:57:54 -0500 Subject: TOOLS: Compile on old platforms such as RHEL5 Provides compatible declarations for modern file management functions such as futimens or opening with the O_CLOEXEC flag --- configure.ac | 4 ++ src/tools/files.c | 177 ++++++++++++++++++++++++++++++++++++++++++------------ 2 files changed, 144 insertions(+), 37 deletions(-) diff --git a/configure.ac b/configure.ac index 2cde25174..9245ae7c0 100644 --- a/configure.ac +++ b/configure.ac @@ -63,6 +63,10 @@ AC_CHECK_FUNCS([ pthread_mutexattr_setrobust \ pthread_mutex_consistent_np ]) LIBS=$SAVE_LIBS +# Check for presence of modern functions for setting file timestamps +AC_CHECK_FUNCS([ utimensat \ + futimens ]) + #Check for PAM headers AC_CHECK_HEADERS([security/pam_appl.h security/pam_misc.h security/pam_modules.h], [AC_CHECK_LIB(pam, pam_get_item, [ PAM_LIBS="-lpam" ], [AC_MSG_ERROR([PAM must support pam_get_item])])], diff --git a/src/tools/files.c b/src/tools/files.c index 3d2273f7d..a3bc51733 100644 --- a/src/tools/files.c +++ b/src/tools/files.c @@ -54,6 +54,8 @@ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ +#include "config.h" + #include #include #include @@ -62,7 +64,6 @@ #include #include -#include "config.h" #include "util/util.h" #include "tools/tools_util.h" @@ -74,6 +75,125 @@ struct copy_ctx { gid_t gid; }; +static int open_cloexec(const char *pathname, int flags, int *ret) +{ + int fd; + int oflags; + + oflags = flags; +#ifdef O_CLOEXEC + oflags |= O_CLOEXEC; +#endif + + errno = 0; + fd = open(pathname, oflags); + if (fd == -1) { + if (ret) { + *ret = errno; + } + return -1; + } + +#ifndef O_CLOEXEC + int v; + + v = fcntl(fd, F_GETFD, 0); + /* we ignore an error, it's not fatal and there is nothing we + * can do about it anyways */ + (void)fcntl(fd, F_SETFD, v | FD_CLOEXEC); +#endif + + return fd; +} + +static int openat_cloexec(int dir_fd, const char *pathname, int flags, int *ret) +{ + int fd; + int oflags; + + oflags = flags; +#ifdef O_CLOEXEC + oflags |= O_CLOEXEC; +#endif + + errno = 0; + fd = openat(dir_fd, pathname, oflags); + if (fd == -1) { + if (ret) { + *ret = errno; + } + return -1; + } + +#ifndef O_CLOEXEC + int v; + + v = fcntl(fd, F_GETFD, 0); + /* we ignore an error, it's not fatal and there is nothing we + * can do about it anyways */ + (void)fcntl(fd, F_SETFD, v | FD_CLOEXEC); +#endif + + return fd; +} + +static int sss_timeat_set(int dir_fd, const char *path, + const struct stat *statp, + int flags) +{ + int ret; + +#ifdef HAVE_UTIMENSAT + struct timespec timebuf[2]; + + timebuf[0] = statp->st_atim; + timebuf[1] = statp->st_mtim; + + ret = utimensat(dir_fd, path, timebuf, flags); +#else + struct timeval tv[2]; + + tv[0].tv_sec = statp->st_atime; + tv[0].tv_usec = 0; + tv[1].tv_sec = statp->st_mtime; + tv[1].tv_usec = 0; + + ret = futimesat(dir_fd, path, tv); +#endif + if (ret == -1) { + return errno; + } + + return EOK; +} + +static int sss_futime_set(int fd, const struct stat *statp) +{ + int ret; + +#ifdef HAVE_FUTIMENS + struct timespec timebuf[2]; + + timebuf[0] = statp->st_atim; + timebuf[1] = statp->st_mtim; + ret = futimens(fd, timebuf); +#else + struct timeval tv[2]; + + tv[0].tv_sec = statp->st_atime; + tv[0].tv_usec = 0; + tv[1].tv_sec = statp->st_mtime; + tv[1].tv_usec = 0; + + ret = futimes(fd, tv); +#endif + if (ret == -1) { + return errno; + } + + return EOK; +} + /* wrapper in order not to create a temporary context in * every iteration */ static int remove_tree_with_ctx(TALLOC_CTX *mem_ctx, @@ -112,8 +232,8 @@ static int remove_tree_with_ctx(TALLOC_CTX *mem_ctx, int ret, err; int dir_fd; - dir_fd = openat(parent_fd, dir_name, - O_RDONLY | O_CLOEXEC | O_DIRECTORY | O_NOFOLLOW); + dir_fd = openat_cloexec(parent_fd, dir_name, + O_RDONLY | O_DIRECTORY | O_NOFOLLOW, &ret); if (dir_fd == -1) { ret = errno; DEBUG(SSSDBG_CRIT_FAILURE, ("Cannot open %s: [%d]: %s\n", @@ -246,7 +366,6 @@ copy_symlink(int src_dir_fd, { char *buf; errno_t ret; - struct timespec timebuf[2]; buf = talloc_readlinkat(NULL, src_dir_fd, file_name); if (!buf) { @@ -283,12 +402,9 @@ copy_symlink(int src_dir_fd, return ret; } - timebuf[0] = statp->st_atim; - timebuf[1] = statp->st_mtim; - ret = utimensat(dst_dir_fd, file_name, timebuf, - AT_SYMLINK_NOFOLLOW); - if (ret == -1) { - ret = errno; + ret = sss_timeat_set(dst_dir_fd, file_name, statp, + AT_SYMLINK_NOFOLLOW); + if (ret != EOK) { DEBUG(SSSDBG_MINOR_FAILURE, ("utimensat failed [%d]: %s\n", ret, strerror(ret))); /* Do not fail */ @@ -309,7 +425,6 @@ static int copy_special(int dst_dir_fd, uid_t uid, gid_t gid) { int ret; - struct timespec timebuf[2]; ret = selinux_file_context(full_path); if (ret != 0) { @@ -346,9 +461,7 @@ static int copy_special(int dst_dir_fd, return ret; } - timebuf[0] = statp->st_atim; - timebuf[1] = statp->st_mtim; - ret = utimensat(dst_dir_fd, file_name, timebuf, 0); + ret = sss_timeat_set(dst_dir_fd, file_name, statp, 0); if (ret == -1) { ret = errno; DEBUG(SSSDBG_MINOR_FAILURE, @@ -376,7 +489,6 @@ copy_file(int ifd, errno_t ret; char buf[1024]; ssize_t cnt, written; - struct timespec timebuf[2]; ret = selinux_file_context(full_path); if (ret != 0) { @@ -443,12 +555,9 @@ copy_file(int ifd, goto done; } - timebuf[0] = statp->st_atim; - timebuf[1] = statp->st_mtim; - ret = futimens(ofd, timebuf); - if (ret == -1) { - ret = errno; - DEBUG(SSSDBG_MINOR_FAILURE, ("futimens failed [%d]: %s\n", + ret = sss_futime_set(ofd, statp); + if (ret != EOK) { + DEBUG(SSSDBG_MINOR_FAILURE, ("sss_futime_set failed [%d]: %s\n", ret, strerror(ret))); /* Do not fail */ } @@ -498,15 +607,14 @@ copy_entry(struct copy_ctx *cctx, * us against FIFOs and perhaps side-effects of the open() of a * device file if there ever was one here, and doesn't matter * for regular files or directories. */ - ifd = openat(src_dir_fd, ent_name, - O_RDONLY | O_CLOEXEC | O_NOFOLLOW | O_NONBLOCK); - if (ifd == -1 && errno != ELOOP) { + ifd = openat_cloexec(src_dir_fd, ent_name, + O_RDONLY | O_NOFOLLOW | O_NONBLOCK, &ret); + if (ifd == -1 && ret != ELOOP) { /* openat error */ - ret = errno; DEBUG(SSSDBG_CRIT_FAILURE, ("openat failed on '%s': %s\n", src_ent_path, strerror(ret))); goto done; - } else if (ifd == -1 && errno == ELOOP) { + } else if (ifd == -1 && ret == ELOOP) { /* Should be a symlink.. */ ret = fstatat(src_dir_fd, ent_name, &st, AT_SYMLINK_NOFOLLOW); if (ret == -1) { @@ -586,7 +694,6 @@ copy_dir(struct copy_ctx *cctx, int dest_dir_fd = -1; DIR *dir = NULL; struct dirent *ent; - struct timespec timebuf[2]; if (!dest_dir_path) { return EINVAL; @@ -613,8 +720,8 @@ copy_dir(struct copy_ctx *cctx, goto done; } - dest_dir_fd = openat(dest_parent_fd, dest_dir_name, - O_RDONLY | O_CLOEXEC | O_DIRECTORY | O_NOFOLLOW); + dest_dir_fd = openat_cloexec(dest_parent_fd, dest_dir_name, + O_RDONLY | O_DIRECTORY | O_NOFOLLOW, &ret); if (dest_dir_fd == -1) { ret = errno; DEBUG(SSSDBG_CRIT_FAILURE, @@ -663,12 +770,9 @@ copy_dir(struct copy_ctx *cctx, goto done; } - timebuf[0] = src_dir_stat->st_atim; - timebuf[1] = src_dir_stat->st_mtim; - futimens(dest_dir_fd, timebuf); - if (ret == -1) { - ret = errno; - DEBUG(SSSDBG_MINOR_FAILURE, ("futimens failed [%d]: %s\n", + sss_futime_set(dest_dir_fd, src_dir_stat); + if (ret != EOK) { + DEBUG(SSSDBG_MINOR_FAILURE, ("sss_futime_set failed [%d]: %s\n", ret, strerror(ret))); /* Do not fail */ } @@ -695,9 +799,8 @@ int copy_tree(const char *src_root, const char *dst_root, int fd = -1; struct stat s_src; - fd = open(src_root, O_RDONLY | O_CLOEXEC | O_DIRECTORY); + fd = open_cloexec(src_root, O_RDONLY | O_DIRECTORY, &ret); if (fd == -1) { - ret = errno; goto fail; } -- cgit