Migrate more fd-concerned functions from wutil into fds

Functions like wopen_cloexec have a new home in fds.cpp. This is in
preparation for reworking how internal fds avoid conflict with user fds.
This commit is contained in:
ridiculousfish 2021-02-02 17:16:26 -08:00
parent 6588cf35f4
commit 4b4bf541d1
7 changed files with 114 additions and 104 deletions

View File

@ -5,11 +5,17 @@
#include "fds.h"
#include <errno.h>
#include <fcntl.h>
#include <unistd.h>
#include "common.h"
#include "flog.h"
#include "wutil.h"
#if defined(__linux__)
#include <sys/statfs.h>
#endif
void autoclose_fd_t::close() {
if (fd_ < 0) return;
exec_close(fd_);
@ -63,6 +69,85 @@ maybe_t<autoclose_pipes_t> make_autoclose_pipes(const fd_set_t &fdset) {
return autoclose_pipes_t(std::move(read_end), std::move(write_end));
}
int set_cloexec(int fd, bool should_set) {
// Note we don't want to overwrite existing flags like O_NONBLOCK which may be set. So fetch the
// existing flags and modify them.
int flags = fcntl(fd, F_GETFD, 0);
if (flags < 0) {
return -1;
}
int new_flags = flags;
if (should_set) {
new_flags |= FD_CLOEXEC;
} else {
new_flags &= ~FD_CLOEXEC;
}
if (flags == new_flags) {
return 0;
} else {
return fcntl(fd, F_SETFD, new_flags);
}
}
int open_cloexec(const std::string &path, int flags, mode_t mode) {
return open_cloexec(path.c_str(), flags, mode);
}
int open_cloexec(const char *path, int flags, mode_t mode) {
int fd;
// Prefer to use O_CLOEXEC.
#ifdef O_CLOEXEC
fd = open(path, flags | O_CLOEXEC, mode);
#else
fd = open(path, flags, mode);
if (fd >= 0 && !set_cloexec(fd)) {
exec_close(fd);
fd = -1;
}
#endif
return fd;
}
int wopen_cloexec(const wcstring &pathname, int flags, mode_t mode) {
return open_cloexec(wcs2string(pathname), flags, mode);
}
int fd_check_is_remote(int fd) {
UNUSED(fd);
#if defined(__linux__)
struct statfs buf {};
if (fstatfs(fd, &buf) < 0) {
return -1;
}
// Linux has constants for these like NFS_SUPER_MAGIC, SMB_SUPER_MAGIC, CIFS_MAGIC_NUMBER but
// these are in varying headers. Simply hard code them.
// NOTE: The cast is necessary for 32-bit systems because of the 4-byte CIFS_MAGIC_NUMBER
switch (static_cast<unsigned int>(buf.f_type)) {
case 0x6969: // NFS_SUPER_MAGIC
case 0x517B: // SMB_SUPER_MAGIC
case 0xFE534D42U: // SMB2_MAGIC_NUMBER - not in the manpage
case 0xFF534D42U: // CIFS_MAGIC_NUMBER
return 1;
default:
// Other FSes are assumed local.
return 0;
}
#elif defined(ST_LOCAL)
// ST_LOCAL is a flag to statvfs, which is itself standardized.
// In practice the only system to use this path is NetBSD.
struct statvfs buf {};
if (fstatvfs(fd, &buf) < 0) return -1;
return (buf.f_flag & ST_LOCAL) ? 0 : 1;
#elif defined(MNT_LOCAL)
struct statfs buf {};
if (fstatfs(fd, &buf) < 0) return -1;
return (buf.f_flags & MNT_LOCAL) ? 0 : 1;
#else
return -1;
#endif
}
void exec_close(int fd) {
assert(fd >= 0 && "Invalid fd");
while (close(fd) == -1) {

View File

@ -4,10 +4,13 @@
#define FISH_FDS_H
#include <algorithm>
#include <string>
#include <vector>
#include "maybe.h"
using wcstring = std::wstring;
/// Pipe redirection error message.
#define PIPE_ERROR _(L"An error occurred while setting up pipe")
@ -95,6 +98,27 @@ maybe_t<autoclose_pipes_t> make_autoclose_pipes(const fd_set_t &fdset);
/// cloexec. \returns invalid fd on failure (in which case the given fd is still closed).
autoclose_fd_t move_fd_to_unused(autoclose_fd_t fd, const fd_set_t &fdset);
/// Sets CLO_EXEC on a given fd according to the value of \p should_set.
int set_cloexec(int fd, bool should_set = true);
/// Wide character version of open() that also sets the close-on-exec flag (atomically when
/// possible).
int wopen_cloexec(const wcstring &pathname, int flags, mode_t mode = 0);
/// Narrow versions of wopen_cloexec.
int open_cloexec(const std::string &path, int flags, mode_t mode = 0);
int open_cloexec(const char *path, int flags, mode_t mode = 0);
/// Mark an fd as nonblocking; returns errno or 0 on success.
int make_fd_nonblocking(int fd);
/// Mark an fd as blocking; returns errno or 0 on success.
int make_fd_blocking(int fd);
/// Check if an fd is on a remote filesystem (NFS, SMB, CFS)
/// Return 1 if remote, 0 if local, -1 on error or if not implemented on this platform.
int fd_check_is_remote(int fd);
/// Close a file descriptor \p fd, retrying on EINTR.
void exec_close(int fd);

View File

@ -39,6 +39,7 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
#include "env.h"
#include "expand.h"
#include "fish_version.h"
#include "fds.h"
#include "flog.h"
#include "highlight.h"
#include "operation_context.h"

View File

@ -2,10 +2,11 @@
#include "history_file.h"
#include <cstring>
#include "fds.h"
#include "history.h"
#include <cstring>
// Some forward declarations.
static history_item_t decode_item_fish_2_0(const char *base, size_t len);
static history_item_t decode_item_fish_1_x(const char *begin, size_t length);

View File

@ -19,6 +19,7 @@
#include <thread>
#include "common.h"
#include "fds.h"
#include "flog.h"
#include "global_safety.h"
#include "wutil.h"

View File

@ -12,9 +12,6 @@
#include <sys/stat.h>
#include <cstring>
#if defined(__linux__)
#include <sys/statfs.h>
#endif
#include <sys/mount.h>
#include <sys/statvfs.h>
#include <sys/types.h>
@ -142,50 +139,6 @@ wcstring wgetcwd() {
return wcstring();
}
int set_cloexec(int fd, bool should_set) {
// Note we don't want to overwrite existing flags like O_NONBLOCK which may be set. So fetch the
// existing flags and modify them.
int flags = fcntl(fd, F_GETFD, 0);
if (flags < 0) {
return -1;
}
int new_flags = flags;
if (should_set) {
new_flags |= FD_CLOEXEC;
} else {
new_flags &= ~FD_CLOEXEC;
}
if (flags == new_flags) {
return 0;
} else {
return fcntl(fd, F_SETFD, new_flags);
}
}
int open_cloexec(const std::string &path, int flags, mode_t mode) {
return open_cloexec(path.c_str(), flags, mode);
}
int open_cloexec(const char *path, int flags, mode_t mode) {
int fd;
// Prefer to use O_CLOEXEC.
#ifdef O_CLOEXEC
fd = open(path, flags | O_CLOEXEC, mode);
#else
fd = open(path, flags, mode);
if (fd >= 0 && !set_cloexec(fd)) {
exec_close(fd);
fd = -1;
}
#endif
return fd;
}
int wopen_cloexec(const wcstring &pathname, int flags, mode_t mode) {
cstring tmp = wcs2string(pathname);
return open_cloexec(tmp, flags, mode);
}
DIR *wopendir(const wcstring &name) {
const cstring tmp = wcs2string(name);
@ -256,40 +209,6 @@ int make_fd_blocking(int fd) {
return err == -1 ? errno : 0;
}
int fd_check_is_remote(int fd) {
#if defined(__linux__)
struct statfs buf {};
if (fstatfs(fd, &buf) < 0) {
return -1;
}
// Linux has constants for these like NFS_SUPER_MAGIC, SMB_SUPER_MAGIC, CIFS_MAGIC_NUMBER but
// these are in varying headers. Simply hard code them.
// NOTE: The cast is necessary for 32-bit systems because of the 4-byte CIFS_MAGIC_NUMBER
switch (static_cast<unsigned int>(buf.f_type)) {
case 0x6969: // NFS_SUPER_MAGIC
case 0x517B: // SMB_SUPER_MAGIC
case 0xFE534D42U: // SMB2_MAGIC_NUMBER - not in the manpage
case 0xFF534D42U: // CIFS_MAGIC_NUMBER
return 1;
default:
// Other FSes are assumed local.
return 0;
}
#elif defined(ST_LOCAL)
// ST_LOCAL is a flag to statvfs, which is itself standardized.
// In practice the only system to use this path is NetBSD.
struct statvfs buf {};
if (fstatvfs(fd, &buf) < 0) return -1;
return (buf.f_flag & ST_LOCAL) ? 0 : 1;
#elif defined(MNT_LOCAL)
struct statfs buf {};
if (fstatfs(fd, &buf) < 0) return -1;
return (buf.f_flags & MNT_LOCAL) ? 0 : 1;
#else
return -1;
#endif
}
static inline void safe_append(char *buffer, const char *s, size_t buffsize) {
std::strncat(buffer, s, buffsize - std::strlen(buffer) - 1);
}

View File

@ -19,27 +19,6 @@
#include "common.h"
#include "maybe.h"
/// Sets CLO_EXEC on a given fd according to the value of \p should_set.
int set_cloexec(int fd, bool should_set = true);
/// Wide character version of open() that also sets the close-on-exec flag (atomically when
/// possible).
int wopen_cloexec(const wcstring &pathname, int flags, mode_t mode = 0);
/// Narrow versions of wopen_cloexec.
int open_cloexec(const std::string &path, int flags, mode_t mode = 0);
int open_cloexec(const char *path, int flags, mode_t mode = 0);
/// Mark an fd as nonblocking; returns errno or 0 on success.
int make_fd_nonblocking(int fd);
/// Mark an fd as blocking; returns errno or 0 on success.
int make_fd_blocking(int fd);
/// Check if an fd is on a remote filesystem (NFS, SMB, CFS)
/// Return 1 if remote, 0 if local, -1 on error or if not implemented on this platform.
int fd_check_is_remote(int fd);
/// Wide character version of opendir(). Note that opendir() is guaranteed to set close-on-exec by
/// POSIX (hooray).
DIR *wopendir(const wcstring &name);