diff options
author | Tom Tromey <tromey@redhat.com> | 2013-04-22 16:46:15 +0000 |
---|---|---|
committer | Tom Tromey <tromey@redhat.com> | 2013-04-22 16:46:15 +0000 |
commit | 614c279dda95dd69c3c14778fc600f4a265847d6 (patch) | |
tree | 9bd77eb734c303ecac4ffdc2477bf0c314b801f5 /gdb/common/filestuff.c | |
parent | 5fda2332f3403df3e1c37da3e3697d6fb6bc4706 (diff) | |
download | gdb-614c279dda95dd69c3c14778fc600f4a265847d6.zip gdb-614c279dda95dd69c3c14778fc600f4a265847d6.tar.gz gdb-614c279dda95dd69c3c14778fc600f4a265847d6.tar.bz2 |
PR gdb/7912:
* Makefile.in (SFILES): Add filestuff.c
(COMMON_OBS): Add filestuff.o.
(filestuff.o): New target.
* auto-load.c (auto_load_objfile_script_1): Use
gdb_fopen_cloexec.
* auxv.c (procfs_xfer_auxv): Use gdb_open_cloexec.
* cli/cli-cmds.c (shell_escape): Call close_most_fds.
* cli/cli-dump.c (fopen_with_cleanup): Use gdb_fopen_cloexec.
* common/agent.c (gdb_connect_sync_socket): Use
gdb_socket_cloexec.
* common/filestuff.c: New file.
* common/filestuff.h: New file.
* common/linux-osdata.c (linux_common_core_of_thread)
(command_from_pid, commandline_from_pid, print_source_lines)
(linux_xfer_osdata_shm, linux_xfer_osdata_sem)
(linux_xfer_osdata_msg, linux_xfer_osdata_modules): Use
gdb_fopen_cloexec.
* common/linux-procfs.c (linux_proc_get_int)
(linux_proc_pid_has_state): Use gdb_fopen_cloexec.
* config.in, configure: Rebuild.
* configure.ac: Don't check for sys/socket.h. Check for
fdwalk, pipe2.
* corelow.c (core_open): Use gdb_open_cloexec.
* dwarf2read.c (write_psymtabs_to_index): Use gdb_fopen_cloexec.
* fork-child.c (fork_inferior): Call close_most_fds.
* gdb_bfd.c (gdb_bfd_open): Use gdb_open_cloexec.
* inf-child.c (inf_child_fileio_readlink): Use gdb_open_cloexec.
* linux-nat.c (linux_nat_thread_name, linux_proc_pending_signals):
Use gdb_fopen_cloexec.
(linux_proc_xfer_partial, linux_proc_xfer_spu): Use
gdb_open_cloexec.
(linux_async_pipe): Use gdb_pipe_cloexec.
* remote-fileio.c (remote_fileio_func_open): Use
gdb_open_cloexec.
* remote.c (remote_file_put, remote_file_get): Use
gdb_fopen_cloexec.
* ser-pipe.c (pipe_open): Use gdb_socketpair_cloexec,
close_most_fds.
* ser-tcp.c (net_open): Use gdb_socket_cloexec.
* ser-unix.c (hardwire_open): Use gdb_open_cloexec.
* solib.c (solib_find): Use gdb_open_cloexec.
* source.c (openp, find_and_open_source): Use gdb_open_cloexec.
* tracepoint.c (tfile_start): Use gdb_fopen_cloexec.
(tfile_open): Use gdb_open_cloexec.
* tui/tui-io.c (tui_initialize_io): Use gdb_pipe_cloexec.
* ui-file.c (gdb_fopen): Use gdb_fopen_cloexec.
* xml-support.c (xml_fetch_content_from_file): Use
gdb_fopen_cloexec.
* main.c (captured_main): Call notice_open_fds.
gdbserver
* Makefile.in (SFILES): Add filestuff.c.
(OBS): Add filestuff.o.
(filestuff.o): New target.
* config.in, configure: Rebuild.
* configure.ac: Check for fdwalk, pipe2.
Diffstat (limited to 'gdb/common/filestuff.c')
-rw-r--r-- | gdb/common/filestuff.c | 354 |
1 files changed, 354 insertions, 0 deletions
diff --git a/gdb/common/filestuff.c b/gdb/common/filestuff.c new file mode 100644 index 0000000..2cc1c4d --- /dev/null +++ b/gdb/common/filestuff.c @@ -0,0 +1,354 @@ +/* Low-level file-handling. + Copyright (C) 2012, 2013 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/>. */ + +#ifdef GDBSERVER +#include "server.h" +#else +#include "defs.h" +#include "gdb_string.h" +#endif +#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 HAVE_SYS_RESOURCE_H +#include <sys/resource.h> +#endif /* HAVE_SYS_RESOURCE_H */ + +#ifndef O_CLOEXEC +#define O_CLOEXEC 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; + int result; + + 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 + + { + int max, fd; + +#ifdef HAVE_GETRLIMIT + 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 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); + +static VEC (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); + return 0; +} + +/* See filestuff.h. */ + +void +notice_open_fds (void) +{ + fdwalk (do_mark_open_fd, NULL); +} + +/* Helper function for close_most_fds that closes the file descriptor + if appropriate. */ + +static int +do_close (void *ignore, int fd) +{ + int i, val; + + for (i = 0; VEC_iterate (int, open_fds, i, val); ++i) + { + 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) +{ + 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; + } + } +} + +/* 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); +} + +/* 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); +} + + + +/* See filestuff.h. */ + +int +gdb_open_cloexec (const char *filename, int flags, mode_t mode) +{ + int fd = open (filename, flags | O_CLOEXEC, mode); + + if (fd >= 0) + maybe_mark_cloexec (fd); + + return fd; +} + +/* See filestuff.h. */ + +FILE * +gdb_fopen_cloexec (const char *filename, const char *opentype) +{ + FILE *result = NULL; + static int fopen_e_ever_failed; + + if (!fopen_e_ever_failed) + { + char *copy; + + copy = 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) + maybe_mark_cloexec (fileno (result)); + + return result; +} + +/* See filestuff.h. */ + +int +gdb_socketpair_cloexec (int namespace, int style, int protocol, int filedes[2]) +{ + int result = socketpair (namespace, style | SOCK_CLOEXEC, protocol, filedes); + + if (result != -1) + { + socket_mark_cloexec (filedes[0]); + socket_mark_cloexec (filedes[1]); + } + + return result; +} + +/* See filestuff.h. */ + +int +gdb_socket_cloexec (int namespace, int style, int protocol) +{ + int result = socket (namespace, style | SOCK_CLOEXEC, protocol); + + if (result != -1) + socket_mark_cloexec (result); + + return result; +} + +/* 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 + result = pipe (filedes); + if (result != -1) + { + mark_cloexec (filedes[0]); + mark_cloexec (filedes[1]); + } +#endif + + return result; +} |