/* Low-level file-handling.
- Copyright (C) 2012, 2013 Free Software Foundation, Inc.
+ Copyright (C) 2012-2018 Free Software Foundation, Inc.
This file is part of GDB.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>. */
-#ifdef GDBSERVER
-#include "server.h"
-#else
-#include "defs.h"
-#include "gdb_string.h"
-#endif
+#include "common-defs.h"
#include "filestuff.h"
#include "gdb_vecs.h"
-
-#include <string.h>
#include <fcntl.h>
#include <unistd.h>
#include <sys/types.h>
-#include "gdb_stat.h"
+#include <sys/stat.h>
+#include <algorithm>
#ifdef USE_WIN32API
#include <winsock2.h>
#include <windows.h>
-#else
+#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_SYS_RESOURCE_H
#ifndef HAVE_FDWALK
-#include "gdb_dirent.h"
+#include <dirent.h>
/* Replacement for fdwalk, if the system doesn't define it. Walks all
open file descriptors (though this implementation may walk closed
{
int max, fd;
-#ifdef HAVE_GETRLIMIT
+#if defined(HAVE_GETRLIMIT) && defined(RLIMIT_NOFILE)
struct rlimit rlim;
if (getrlimit (RLIMIT_NOFILE, &rlim) == 0 && rlim.rlim_max != RLIM_INFINITY)
\f
-/* A VEC holding all the fds open when notice_open_fds was called. We
- don't use a hashtab because libiberty isn't linked into gdbserver;
- and anyway we don't expect there to be many open fds. */
-
-DEF_VEC_I (int);
+/* 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 VEC (int) *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)
{
- VEC_safe_push (int, open_fds, fd);
+ open_fds.push_back (fd);
return 0;
}
void
unmark_fd_no_cloexec (int fd)
{
- int i, val;
-
- for (i = 0; VEC_iterate (int, open_fds, i, val); ++i)
- {
- if (fd == val)
- {
- VEC_unordered_remove (int, open_fds, i);
- return;
- }
- }
+ auto it = std::remove (open_fds.begin (), open_fds.end (), fd);
- gdb_assert_not_reached (_("fd not found in open_fds"));
+ 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
static int
do_close (void *ignore, int fd)
{
- int i, val;
-
- for (i = 0; VEC_iterate (int, open_fds, i, val); ++i)
+ for (int val : open_fds)
{
if (fd == val)
{
mark_cloexec (fd);
}
+#ifdef HAVE_SOCKETS
+
/* Like maybe_mark_cloexec, but for callers that use SOCK_CLOEXEC. */
static void
mark_cloexec (fd);
}
+#endif
+
\f
/* See filestuff.h. */
/* See filestuff.h. */
-FILE *
+gdb_file_up
gdb_fopen_cloexec (const char *filename, const char *opentype)
{
- FILE *result = NULL;
- static int fopen_e_ever_failed;
-
- if (!fopen_e_ever_failed)
+ 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. */
+ static int fopen_e_ever_failed_einval = O_CLOEXEC == 0;
+
+ if (!fopen_e_ever_failed_einval)
{
char *copy;
- copy = alloca (strlen (opentype) + 2);
+ 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)
- {
- /* Fallback. */
- result = fopen (filename, opentype);
- if (result != NULL)
- fopen_e_ever_failed = 1;
+ 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 result;
+ return gdb_file_up (result);
}
+#ifdef HAVE_SOCKETS
/* See filestuff.h. */
int
-gdb_socketpair_cloexec (int namespace, int style, int protocol, int filedes[2])
+gdb_socketpair_cloexec (int domain, int style, int protocol,
+ int filedes[2])
{
#ifdef HAVE_SOCKETPAIR
- int result = socketpair (namespace, style | SOCK_CLOEXEC, protocol, filedes);
+ int result = socketpair (domain, style | SOCK_CLOEXEC, protocol, filedes);
if (result != -1)
{
/* See filestuff.h. */
int
-gdb_socket_cloexec (int namespace, int style, int protocol)
+gdb_socket_cloexec (int domain, int style, int protocol)
{
- int result = socket (namespace, style | SOCK_CLOEXEC, protocol);
+ int result = socket (domain, style | SOCK_CLOEXEC, protocol);
if (result != -1)
socket_mark_cloexec (result);
return result;
}
+#endif
/* See filestuff.h. */
return result;
}
+
+/* Helper function which does the work for make_cleanup_close. */
+
+static void
+do_close_cleanup (void *arg)
+{
+ int *fd = (int *) arg;
+
+ close (*fd);
+}
+
+/* See filestuff.h. */
+
+struct cleanup *
+make_cleanup_close (int fd)
+{
+ int *saved_fd = XNEW (int);
+
+ *saved_fd = fd;
+ return make_cleanup_dtor (do_close_cleanup, saved_fd, xfree);
+}
+
+/* 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;
+}