diff --git a/gnulib/lib/Makefile.am b/gnulib/lib/Makefile.am index 20bbb18ff..d2f73cbe0 100644 --- a/gnulib/lib/Makefile.am +++ b/gnulib/lib/Makefile.am @@ -23,6 +23,7 @@ include $(top_srcdir)/subdir-rules.mk noinst_LTLIBRARIES = libgnu.la libgnu_la_SOURCES = \ + accept4.c \ base64.c \ base64.h \ bitrotate.h \ @@ -41,6 +42,7 @@ libgnu_la_SOURCES = \ ignore-value.h \ nonblocking.c \ nonblocking.h \ + pipe2.c \ safe-read.c \ safe-read.h \ safe-write.c \ diff --git a/gnulib/lib/accept4.c b/gnulib/lib/accept4.c new file mode 100644 index 000000000..284973025 --- /dev/null +++ b/gnulib/lib/accept4.c @@ -0,0 +1,155 @@ +/* Accept a connection on a socket, with specific opening flags. + Copyright (C) 2009-2022 Free Software Foundation, Inc. + + This file is free software: you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License as + published by the Free Software Foundation, either version 3 of the + License, or (at your option) any later version. + + This file is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with this program. If not, see . */ + +#include + +/* Specification. */ +#include + +#include +#include +#if GNULIB_MSVC_NOTHROW +# include "msvc-nothrow.h" +#endif + +#ifndef SOCK_CLOEXEC +# define SOCK_CLOEXEC 0 +#endif +#ifndef SOCK_NONBLOCK +# define SOCK_NONBLOCK 0 +#endif + +#ifndef O_TEXT +#define O_TEXT 0 +#endif +#ifndef O_BINARY +#define O_BINARY 0 +#endif + +int +accept4 (int sockfd, struct sockaddr *addr, socklen_t *addrlen, int flags) +{ + int fd; + +#if HAVE_DECL_ACCEPT4 +# undef accept4 + /* Try the system call first, if it exists. (We may be running with a glibc + that has the function but with an older kernel that lacks it.) */ + { + /* Cache the information whether the system call really exists. */ + static int have_accept4_really; /* 0 = unknown, 1 = yes, -1 = no */ + if (have_accept4_really >= 0) + { + int result = accept4 (sockfd, addr, addrlen, flags); + if (!(result < 0 && errno == ENOSYS)) + { + have_accept4_really = 1; + return result; + } + have_accept4_really = -1; + } + } +#endif + + /* Check the supported flags. */ + if ((flags & ~(SOCK_CLOEXEC | SOCK_NONBLOCK | O_TEXT | O_BINARY)) != 0) + { + errno = EINVAL; + return -1; + } + + fd = accept (sockfd, addr, addrlen); + if (fd < 0) + return -1; + +#if SOCK_CLOEXEC +# if defined _WIN32 && ! defined __CYGWIN__ +/* Native Windows API. */ + if (flags & SOCK_CLOEXEC) + { + HANDLE curr_process = GetCurrentProcess (); + HANDLE old_handle = (HANDLE) _get_osfhandle (fd); + HANDLE new_handle; + int nfd; + + if (!DuplicateHandle (curr_process, /* SourceProcessHandle */ + old_handle, /* SourceHandle */ + curr_process, /* TargetProcessHandle */ + (PHANDLE) &new_handle, /* TargetHandle */ + (DWORD) 0, /* DesiredAccess */ + FALSE, /* InheritHandle */ + DUPLICATE_SAME_ACCESS)) /* Options */ + { + close (fd); + errno = EBADF; /* arbitrary */ + return -1; + } + + /* Closing fd before allocating the new fd ensures that the new fd will + have the minimum possible value. */ + close (fd); + nfd = _open_osfhandle ((intptr_t) new_handle, + O_NOINHERIT | (flags & (O_TEXT | O_BINARY))); + if (nfd < 0) + { + CloseHandle (new_handle); + return -1; + } + return nfd; + } +# else +/* Unix API. */ + if (flags & SOCK_CLOEXEC) + { + int fcntl_flags; + + if ((fcntl_flags = fcntl (fd, F_GETFD, 0)) < 0 + || fcntl (fd, F_SETFD, fcntl_flags | FD_CLOEXEC) == -1) + { + int saved_errno = errno; + close (fd); + errno = saved_errno; + return -1; + } + } +# endif +#endif + +#if SOCK_NONBLOCK + if (flags & SOCK_NONBLOCK) + { + int fcntl_flags; + + if ((fcntl_flags = fcntl (fd, F_GETFL, 0)) < 0 + || fcntl (fd, F_SETFL, fcntl_flags | O_NONBLOCK) == -1) + { + int saved_errno = errno; + close (fd); + errno = saved_errno; + return -1; + } + } +#endif + +#if O_BINARY + if (flags & O_BINARY) + set_binary_mode (fd, O_BINARY); + else if (flags & O_TEXT) + set_binary_mode (fd, O_TEXT); +#endif + + return fd; +} diff --git a/gnulib/lib/pipe2.c b/gnulib/lib/pipe2.c new file mode 100644 index 000000000..ab8dd6c61 --- /dev/null +++ b/gnulib/lib/pipe2.c @@ -0,0 +1,171 @@ +/* Create a pipe, with specific opening flags. + Copyright (C) 2009-2022 Free Software Foundation, Inc. + + This file is free software: you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License as + published by the Free Software Foundation; either version 2.1 of the + License, or (at your option) any later version. + + This file is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with this program. If not, see . */ + +#include + +/* Specification. */ +#include + +#include +#include + +#if GNULIB_defined_O_NONBLOCK +# include "nonblocking.h" +#endif + +#if defined _WIN32 && ! defined __CYGWIN__ +/* Native Windows API. */ + +# include + +#endif + +#ifndef O_TEXT +#define O_TEXT 0 +#endif +#ifndef O_BINARY +#define O_BINARY 0 +#endif + +int +pipe2 (int fd[2], int flags) +{ + /* Mingw _pipe() corrupts fd on failure; also, if we succeed at + creating the pipe but later fail at changing fcntl, we want + to leave fd unchanged: http://austingroupbugs.net/view.php?id=467 */ + int tmp[2]; + tmp[0] = fd[0]; + tmp[1] = fd[1]; + +#if HAVE_PIPE2 +# undef pipe2 + /* Try the system call first, if it exists. (We may be running with a glibc + that has the function but with an older kernel that lacks it.) */ + { + /* Cache the information whether the system call really exists. */ + static int have_pipe2_really; /* 0 = unknown, 1 = yes, -1 = no */ + if (have_pipe2_really >= 0) + { + int result = pipe2 (fd, flags); + if (!(result < 0 && errno == ENOSYS)) + { + have_pipe2_really = 1; + return result; + } + have_pipe2_really = -1; + } + } +#endif + + /* Check the supported flags. */ + if ((flags & ~(O_CLOEXEC | O_NONBLOCK | O_BINARY | O_TEXT)) != 0) + { + errno = EINVAL; + return -1; + } + +#if defined _WIN32 && ! defined __CYGWIN__ +/* Native Windows API. */ + + if (_pipe (fd, 4096, flags & ~O_NONBLOCK) < 0) + { + fd[0] = tmp[0]; + fd[1] = tmp[1]; + return -1; + } + + /* O_NONBLOCK handling. + On native Windows platforms, O_NONBLOCK is defined by gnulib. Use the + functions defined by the gnulib module 'nonblocking'. */ +# if GNULIB_defined_O_NONBLOCK + if (flags & O_NONBLOCK) + { + if (set_nonblocking_flag (fd[0], true) != 0 + || set_nonblocking_flag (fd[1], true) != 0) + goto fail; + } +# else + { + verify (O_NONBLOCK == 0); + } +# endif + + return 0; + +#else +/* Unix API. */ + + if (pipe (fd) < 0) + return -1; + + /* POSIX + says that initially, the O_NONBLOCK and FD_CLOEXEC flags are cleared on + both fd[0] and fd[1]. */ + + /* O_NONBLOCK handling. + On Unix platforms, O_NONBLOCK is defined by the system. Use fcntl(). */ + if (flags & O_NONBLOCK) + { + int fcntl_flags; + + if ((fcntl_flags = fcntl (fd[1], F_GETFL, 0)) < 0 + || fcntl (fd[1], F_SETFL, fcntl_flags | O_NONBLOCK) == -1 + || (fcntl_flags = fcntl (fd[0], F_GETFL, 0)) < 0 + || fcntl (fd[0], F_SETFL, fcntl_flags | O_NONBLOCK) == -1) + goto fail; + } + + if (flags & O_CLOEXEC) + { + int fcntl_flags; + + if ((fcntl_flags = fcntl (fd[1], F_GETFD, 0)) < 0 + || fcntl (fd[1], F_SETFD, fcntl_flags | FD_CLOEXEC) == -1 + || (fcntl_flags = fcntl (fd[0], F_GETFD, 0)) < 0 + || fcntl (fd[0], F_SETFD, fcntl_flags | FD_CLOEXEC) == -1) + goto fail; + } + +# if O_BINARY + if (flags & O_BINARY) + { + set_binary_mode (fd[1], O_BINARY); + set_binary_mode (fd[0], O_BINARY); + } + else if (flags & O_TEXT) + { + set_binary_mode (fd[1], O_TEXT); + set_binary_mode (fd[0], O_TEXT); + } +# endif + + return 0; + +#endif + +#if GNULIB_defined_O_NONBLOCK || !(defined _WIN32 && ! defined __CYGWIN__) + fail: + { + int saved_errno = errno; + close (fd[0]); + close (fd[1]); + fd[0] = tmp[0]; + fd[1] = tmp[1]; + errno = saved_errno; + return -1; + } +#endif +} diff --git a/lib/guestfs-internal-all.h b/lib/guestfs-internal-all.h index 090d05c86..98b88e961 100644 --- a/lib/guestfs-internal-all.h +++ b/lib/guestfs-internal-all.h @@ -152,4 +152,16 @@ typedef enum { MOUNTABLE_PATH /* An already mounted path: device = path */ } mountable_type_t; +/* Some functions replaced by gnulib */ +#ifndef HAVE_ACCEPT4 +#include + +extern int accept4 (int sockfd, struct sockaddr *restrict addr, + socklen_t *restrict addrlen, int flags); +#endif + +#ifndef HAVE_PIPE2 +extern int pipe2(int pipefd[2], int flags); +#endif + #endif /* GUESTFS_INTERNAL_ALL_H_ */ diff --git a/m4/guestfs-libraries.m4 b/m4/guestfs-libraries.m4 index 26d9ca3e9..763559faa 100644 --- a/m4/guestfs-libraries.m4 +++ b/m4/guestfs-libraries.m4 @@ -64,6 +64,7 @@ AC_CHECK_HEADERS([\ dnl Functions. AC_CHECK_FUNCS([\ + accept4 \ be32toh \ fsync \ futimens \ @@ -79,6 +80,7 @@ AC_CHECK_FUNCS([\ mknod \ ntohl \ ntohs \ + pipe2 \ posix_fallocate \ posix_fadvise \ removexattr \