/* Low-level file-handling.
- Copyright (C) 2012, 2013 Free Software Foundation, Inc.
+ Copyright (C) 2012-2016 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/socket.h>
#include <sys/types.h>
#include <sys/stat.h>
+#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_SYS_RESOURCE_H
#include <sys/resource.h>
#endif /* HAVE_SYS_RESOURCE_H */
{
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)
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);
-
static VEC (int) *open_fds;
/* An fdwalk callback function used by notice_open_fds. It puts the
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)
+{
+ 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;
+ }
+ }
+
+ gdb_assert_not_reached (_("fd not found in open_fds"));
+}
+
/* Helper function for close_most_fds that closes the file descriptor
if appropriate. */
static void
mark_cloexec (int fd)
{
+#ifdef HAVE_F_GETFD
int old = fcntl (fd, F_GETFD, 0);
if (old != -1)
trust_o_cloexec = -1;
}
}
+#endif /* HAVE_F_GETFD */
}
/* Depending on TRUST_O_CLOEXEC, mark FD as close-on-exec. */
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. */
int
-gdb_open_cloexec (const char *filename, int flags, mode_t mode)
+gdb_open_cloexec (const char *filename, int flags, unsigned long mode)
{
int fd = open (filename, flags | O_CLOEXEC, mode);
FILE *
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;
}
+#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])
{
- int result = socketpair (namespace, style | SOCK_CLOEXEC, protocol, filedes);
+#ifdef HAVE_SOCKETPAIR
+ int result = socketpair (domain, style | SOCK_CLOEXEC, protocol, filedes);
if (result != -1)
{
}
return result;
+#else
+ gdb_assert_not_reached (_("socketpair not available on this host"));
+#endif
}
/* 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. */
maybe_mark_cloexec (filedes[1]);
}
#else
+#ifdef HAVE_PIPE
result = pipe (filedes);
if (result != -1)
{
mark_cloexec (filedes[0]);
mark_cloexec (filedes[1]);
}
-#endif
+#else /* HAVE_PIPE */
+ gdb_assert_not_reached (_("pipe not available on this host"));
+#endif /* HAVE_PIPE */
+#endif /* HAVE_PIPE2 */
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);
+}