diff options
Diffstat (limited to 'gdb/common/filestuff.c')
-rw-r--r-- | gdb/common/filestuff.c | 503 |
1 files changed, 0 insertions, 503 deletions
diff --git a/gdb/common/filestuff.c b/gdb/common/filestuff.c deleted file mode 100644 index c7b8c69..0000000 --- a/gdb/common/filestuff.c +++ /dev/null @@ -1,503 +0,0 @@ -/* Low-level file-handling. - Copyright (C) 2012-2019 Free Software Foundation, Inc. - - This file is part of GDB. - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 3 of the License, or - (at your option) any later version. - - This program 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 General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program. If not, see <http://www.gnu.org/licenses/>. */ - -#include "common-defs.h" -#include "filestuff.h" -#include "gdb_vecs.h" -#include <fcntl.h> -#include <unistd.h> -#include <sys/types.h> -#include <sys/stat.h> -#include <algorithm> - -#ifdef USE_WIN32API -#include <winsock2.h> -#include <windows.h> -#define HAVE_SOCKETS 1 -#elif defined HAVE_SYS_SOCKET_H -#include <sys/socket.h> -/* Define HAVE_F_GETFD if we plan to use F_GETFD. */ -#define HAVE_F_GETFD F_GETFD -#define HAVE_SOCKETS 1 -#endif - -#ifdef HAVE_KINFO_GETFILE -#include <sys/user.h> -#include <libutil.h> -#endif - -#ifdef HAVE_SYS_RESOURCE_H -#include <sys/resource.h> -#endif /* HAVE_SYS_RESOURCE_H */ - -#ifndef O_CLOEXEC -#define O_CLOEXEC 0 -#endif - -#ifndef O_NOINHERIT -#define O_NOINHERIT 0 -#endif - -#ifndef SOCK_CLOEXEC -#define SOCK_CLOEXEC 0 -#endif - - - -#ifndef HAVE_FDWALK - -#include <dirent.h> - -/* Replacement for fdwalk, if the system doesn't define it. Walks all - open file descriptors (though this implementation may walk closed - ones as well, depending on the host platform's capabilities) and - call FUNC with ARG. If FUNC returns non-zero, stops immediately - and returns the same value. Otherwise, returns zero when - finished. */ - -static int -fdwalk (int (*func) (void *, int), void *arg) -{ - /* Checking __linux__ isn't great but it isn't clear what would be - better. There doesn't seem to be a good way to check for this in - configure. */ -#ifdef __linux__ - DIR *dir; - - dir = opendir ("/proc/self/fd"); - if (dir != NULL) - { - struct dirent *entry; - int result = 0; - - for (entry = readdir (dir); entry != NULL; entry = readdir (dir)) - { - long fd; - char *tail; - - errno = 0; - fd = strtol (entry->d_name, &tail, 10); - if (*tail != '\0' || errno != 0) - continue; - if ((int) fd != fd) - { - /* What can we do here really? */ - continue; - } - - if (fd == dirfd (dir)) - continue; - - result = func (arg, fd); - if (result != 0) - break; - } - - closedir (dir); - return result; - } - /* We may fall through to the next case. */ -#endif -#ifdef HAVE_KINFO_GETFILE - int nfd; - gdb::unique_xmalloc_ptr<struct kinfo_file[]> fdtbl - (kinfo_getfile (getpid (), &nfd)); - if (fdtbl != NULL) - { - for (int i = 0; i < nfd; i++) - { - if (fdtbl[i].kf_fd >= 0) - { - int result = func (arg, fdtbl[i].kf_fd); - if (result != 0) - return result; - } - } - return 0; - } - /* We may fall through to the next case. */ -#endif - - { - int max, fd; - -#if defined(HAVE_GETRLIMIT) && defined(RLIMIT_NOFILE) - struct rlimit rlim; - - if (getrlimit (RLIMIT_NOFILE, &rlim) == 0 && rlim.rlim_max != RLIM_INFINITY) - max = rlim.rlim_max; - else -#endif - { -#ifdef _SC_OPEN_MAX - max = sysconf (_SC_OPEN_MAX); -#else - /* Whoops. */ - return 0; -#endif /* _SC_OPEN_MAX */ - } - - for (fd = 0; fd < max; ++fd) - { - struct stat sb; - int result; - - /* Only call FUNC for open fds. */ - if (fstat (fd, &sb) == -1) - continue; - - result = func (arg, fd); - if (result != 0) - return result; - } - - return 0; - } -} - -#endif /* HAVE_FDWALK */ - - - -/* A vector holding all the fds open when notice_open_fds was called. We - don't use a hashtab because we don't expect there to be many open fds. */ - -static std::vector<int> open_fds; - -/* An fdwalk callback function used by notice_open_fds. It puts the - given file descriptor into the vec. */ - -static int -do_mark_open_fd (void *ignore, int fd) -{ - open_fds.push_back (fd); - return 0; -} - -/* See filestuff.h. */ - -void -notice_open_fds (void) -{ - fdwalk (do_mark_open_fd, NULL); -} - -/* See filestuff.h. */ - -void -mark_fd_no_cloexec (int fd) -{ - do_mark_open_fd (NULL, fd); -} - -/* See filestuff.h. */ - -void -unmark_fd_no_cloexec (int fd) -{ - auto it = std::remove (open_fds.begin (), open_fds.end (), fd); - - if (it != open_fds.end ()) - open_fds.erase (it); - else - gdb_assert_not_reached (_("fd not found in open_fds")); -} - -/* Helper function for close_most_fds that closes the file descriptor - if appropriate. */ - -static int -do_close (void *ignore, int fd) -{ - for (int val : open_fds) - { - if (fd == val) - { - /* Keep this one open. */ - return 0; - } - } - - close (fd); - return 0; -} - -/* See filestuff.h. */ - -void -close_most_fds (void) -{ - fdwalk (do_close, NULL); -} - - - -/* This is a tri-state flag. When zero it means we haven't yet tried - O_CLOEXEC. When positive it means that O_CLOEXEC works on this - host. When negative, it means that O_CLOEXEC doesn't work. We - track this state because, while gdb might have been compiled - against a libc that supplies O_CLOEXEC, there is no guarantee that - the kernel supports it. */ - -static int trust_o_cloexec; - -/* Mark FD as close-on-exec, ignoring errors. Update - TRUST_O_CLOEXEC. */ - -static void -mark_cloexec (int fd) -{ -#ifdef HAVE_F_GETFD - int old = fcntl (fd, F_GETFD, 0); - - if (old != -1) - { - fcntl (fd, F_SETFD, old | FD_CLOEXEC); - - if (trust_o_cloexec == 0) - { - if ((old & FD_CLOEXEC) != 0) - trust_o_cloexec = 1; - else - trust_o_cloexec = -1; - } - } -#endif /* HAVE_F_GETFD */ -} - -/* Depending on TRUST_O_CLOEXEC, mark FD as close-on-exec. */ - -static void -maybe_mark_cloexec (int fd) -{ - if (trust_o_cloexec <= 0) - mark_cloexec (fd); -} - -#ifdef HAVE_SOCKETS - -/* Like maybe_mark_cloexec, but for callers that use SOCK_CLOEXEC. */ - -static void -socket_mark_cloexec (int fd) -{ - if (SOCK_CLOEXEC == 0 || trust_o_cloexec <= 0) - mark_cloexec (fd); -} - -#endif - - - -/* See filestuff.h. */ - -int -gdb_open_cloexec (const char *filename, int flags, unsigned long mode) -{ - int fd = open (filename, flags | O_CLOEXEC, mode); - - if (fd >= 0) - maybe_mark_cloexec (fd); - - return fd; -} - -/* See filestuff.h. */ - -gdb_file_up -gdb_fopen_cloexec (const char *filename, const char *opentype) -{ - FILE *result; - /* Probe for "e" support once. But, if we can tell the operating - system doesn't know about close on exec mode "e" without probing, - skip it. E.g., the Windows runtime issues an "Invalid parameter - passed to C runtime function" OutputDebugString warning for - unknown modes. Assume that if O_CLOEXEC is zero, then "e" isn't - supported. On MinGW, O_CLOEXEC is an alias of O_NOINHERIT, and - "e" isn't supported. */ - static int fopen_e_ever_failed_einval = - O_CLOEXEC == 0 || O_CLOEXEC == O_NOINHERIT; - - if (!fopen_e_ever_failed_einval) - { - char *copy; - - copy = (char *) alloca (strlen (opentype) + 2); - strcpy (copy, opentype); - /* This is a glibc extension but we try it unconditionally on - this path. */ - strcat (copy, "e"); - result = fopen (filename, copy); - - if (result == NULL && errno == EINVAL) - { - result = fopen (filename, opentype); - if (result != NULL) - fopen_e_ever_failed_einval = 1; - } - } - else - result = fopen (filename, opentype); - - if (result != NULL) - maybe_mark_cloexec (fileno (result)); - - return gdb_file_up (result); -} - -#ifdef HAVE_SOCKETS -/* See filestuff.h. */ - -int -gdb_socketpair_cloexec (int domain, int style, int protocol, - int filedes[2]) -{ -#ifdef HAVE_SOCKETPAIR - int result = socketpair (domain, style | SOCK_CLOEXEC, protocol, filedes); - - if (result != -1) - { - socket_mark_cloexec (filedes[0]); - socket_mark_cloexec (filedes[1]); - } - - return result; -#else - gdb_assert_not_reached (_("socketpair not available on this host")); -#endif -} - -/* See filestuff.h. */ - -int -gdb_socket_cloexec (int domain, int style, int protocol) -{ - int result = socket (domain, style | SOCK_CLOEXEC, protocol); - - if (result != -1) - socket_mark_cloexec (result); - - return result; -} -#endif - -/* See filestuff.h. */ - -int -gdb_pipe_cloexec (int filedes[2]) -{ - int result; - -#ifdef HAVE_PIPE2 - result = pipe2 (filedes, O_CLOEXEC); - if (result != -1) - { - maybe_mark_cloexec (filedes[0]); - maybe_mark_cloexec (filedes[1]); - } -#else -#ifdef HAVE_PIPE - result = pipe (filedes); - if (result != -1) - { - mark_cloexec (filedes[0]); - mark_cloexec (filedes[1]); - } -#else /* HAVE_PIPE */ - gdb_assert_not_reached (_("pipe not available on this host")); -#endif /* HAVE_PIPE */ -#endif /* HAVE_PIPE2 */ - - return result; -} - -/* See common/filestuff.h. */ - -bool -is_regular_file (const char *name, int *errno_ptr) -{ - struct stat st; - const int status = stat (name, &st); - - /* Stat should never fail except when the file does not exist. - If stat fails, analyze the source of error and return true - unless the file does not exist, to avoid returning false results - on obscure systems where stat does not work as expected. */ - - if (status != 0) - { - if (errno != ENOENT) - return true; - *errno_ptr = ENOENT; - return false; - } - - if (S_ISREG (st.st_mode)) - return true; - - if (S_ISDIR (st.st_mode)) - *errno_ptr = EISDIR; - else - *errno_ptr = EINVAL; - return false; -} - -/* See common/filestuff.h. */ - -bool -mkdir_recursive (const char *dir) -{ - auto holder = make_unique_xstrdup (dir); - char * const start = holder.get (); - char *component_start = start; - char *component_end = start; - - while (1) - { - /* Find the beginning of the next component. */ - while (*component_start == '/') - component_start++; - - /* Are we done? */ - if (*component_start == '\0') - return true; - - /* Find the slash or null-terminator after this component. */ - component_end = component_start; - while (*component_end != '/' && *component_end != '\0') - component_end++; - - /* Temporarily replace the slash with a null terminator, so we can create - the directory up to this component. */ - char saved_char = *component_end; - *component_end = '\0'; - - /* If we get EEXIST and the existing path is a directory, then we're - happy. If it exists, but it's a regular file and this is not the last - component, we'll fail at the next component. If this is the last - component, the caller will fail with ENOTDIR when trying to - open/create a file under that path. */ - if (mkdir (start, 0700) != 0) - if (errno != EEXIST) - return false; - - /* Restore the overwritten char. */ - *component_end = saved_char; - component_start = component_end; - } -} |