aboutsummaryrefslogtreecommitdiff
path: root/gdb/common/filestuff.c
diff options
context:
space:
mode:
Diffstat (limited to 'gdb/common/filestuff.c')
-rw-r--r--gdb/common/filestuff.c503
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;
- }
-}