fd-close-on-exec.c revision 76b43e4417bab52e913da39b5f5bc2a130d3f149
316cbe323513a0f20d1cf519fe9405e231d633e2Aki Tuomi/* Copyright (c) 2002-2008 Dovecot authors, see the included COPYING file */
316cbe323513a0f20d1cf519fe9405e231d633e2Aki Tuomi
316cbe323513a0f20d1cf519fe9405e231d633e2Aki Tuomi#include "lib.h"
316cbe323513a0f20d1cf519fe9405e231d633e2Aki Tuomi#include "network.h"
316cbe323513a0f20d1cf519fe9405e231d633e2Aki Tuomi#include "fd-close-on-exec.h"
316cbe323513a0f20d1cf519fe9405e231d633e2Aki Tuomi
316cbe323513a0f20d1cf519fe9405e231d633e2Aki Tuomi#include <unistd.h>
316cbe323513a0f20d1cf519fe9405e231d633e2Aki Tuomi#include <fcntl.h>
316cbe323513a0f20d1cf519fe9405e231d633e2Aki Tuomi#include <sys/stat.h>
316cbe323513a0f20d1cf519fe9405e231d633e2Aki Tuomi#include <sys/un.h>
316cbe323513a0f20d1cf519fe9405e231d633e2Aki Tuomi
316cbe323513a0f20d1cf519fe9405e231d633e2Aki Tuomivoid fd_close_on_exec(int fd, bool set)
316cbe323513a0f20d1cf519fe9405e231d633e2Aki Tuomi{
316cbe323513a0f20d1cf519fe9405e231d633e2Aki Tuomi int flags;
316cbe323513a0f20d1cf519fe9405e231d633e2Aki Tuomi
316cbe323513a0f20d1cf519fe9405e231d633e2Aki Tuomi flags = fcntl(fd, F_GETFD, 0);
316cbe323513a0f20d1cf519fe9405e231d633e2Aki Tuomi if (flags < 0)
316cbe323513a0f20d1cf519fe9405e231d633e2Aki Tuomi i_fatal("fcntl(F_GETFD, %d) failed: %m", fd);
316cbe323513a0f20d1cf519fe9405e231d633e2Aki Tuomi
316cbe323513a0f20d1cf519fe9405e231d633e2Aki Tuomi flags = set ? (flags | FD_CLOEXEC) : (flags & ~FD_CLOEXEC);
316cbe323513a0f20d1cf519fe9405e231d633e2Aki Tuomi if (fcntl(fd, F_SETFD, flags) < 0)
316cbe323513a0f20d1cf519fe9405e231d633e2Aki Tuomi i_fatal("fcntl(F_SETFD, %d) failed: %m", fd);
316cbe323513a0f20d1cf519fe9405e231d633e2Aki Tuomi}
316cbe323513a0f20d1cf519fe9405e231d633e2Aki Tuomi
316cbe323513a0f20d1cf519fe9405e231d633e2Aki Tuomivoid fd_debug_verify_leaks(int first_fd, int last_fd)
316cbe323513a0f20d1cf519fe9405e231d633e2Aki Tuomi{
316cbe323513a0f20d1cf519fe9405e231d633e2Aki Tuomi struct ip_addr addr, raddr;
316cbe323513a0f20d1cf519fe9405e231d633e2Aki Tuomi unsigned int port, rport;
316cbe323513a0f20d1cf519fe9405e231d633e2Aki Tuomi struct stat st;
316cbe323513a0f20d1cf519fe9405e231d633e2Aki Tuomi int old_errno;
316cbe323513a0f20d1cf519fe9405e231d633e2Aki Tuomi
316cbe323513a0f20d1cf519fe9405e231d633e2Aki Tuomi for (; first_fd < last_fd; first_fd++) {
316cbe323513a0f20d1cf519fe9405e231d633e2Aki Tuomi if (fcntl(first_fd, F_GETFD, 0) == -1 && errno == EBADF)
316cbe323513a0f20d1cf519fe9405e231d633e2Aki Tuomi continue;
316cbe323513a0f20d1cf519fe9405e231d633e2Aki Tuomi
316cbe323513a0f20d1cf519fe9405e231d633e2Aki Tuomi old_errno = errno;
316cbe323513a0f20d1cf519fe9405e231d633e2Aki Tuomi
316cbe323513a0f20d1cf519fe9405e231d633e2Aki Tuomi if (net_getsockname(first_fd, &addr, &port) == 0) {
316cbe323513a0f20d1cf519fe9405e231d633e2Aki Tuomi if (addr.family == AF_UNIX) {
316cbe323513a0f20d1cf519fe9405e231d633e2Aki Tuomi struct sockaddr_un sa;
316cbe323513a0f20d1cf519fe9405e231d633e2Aki Tuomi
316cbe323513a0f20d1cf519fe9405e231d633e2Aki Tuomi socklen_t socklen = sizeof(sa);
316cbe323513a0f20d1cf519fe9405e231d633e2Aki Tuomi
316cbe323513a0f20d1cf519fe9405e231d633e2Aki Tuomi if (getsockname(first_fd, (void *)&sa,
316cbe323513a0f20d1cf519fe9405e231d633e2Aki Tuomi &socklen) < 0)
316cbe323513a0f20d1cf519fe9405e231d633e2Aki Tuomi sa.sun_path[0] = '\0';
316cbe323513a0f20d1cf519fe9405e231d633e2Aki Tuomi
316cbe323513a0f20d1cf519fe9405e231d633e2Aki Tuomi i_panic("Leaked UNIX socket fd %d: %s",
316cbe323513a0f20d1cf519fe9405e231d633e2Aki Tuomi first_fd, sa.sun_path);
316cbe323513a0f20d1cf519fe9405e231d633e2Aki Tuomi }
316cbe323513a0f20d1cf519fe9405e231d633e2Aki Tuomi
316cbe323513a0f20d1cf519fe9405e231d633e2Aki Tuomi if (net_getpeername(first_fd, &raddr, &rport) < 0) {
316cbe323513a0f20d1cf519fe9405e231d633e2Aki Tuomi memset(&raddr, 0, sizeof(raddr));
316cbe323513a0f20d1cf519fe9405e231d633e2Aki Tuomi rport = 0;
316cbe323513a0f20d1cf519fe9405e231d633e2Aki Tuomi }
316cbe323513a0f20d1cf519fe9405e231d633e2Aki Tuomi i_panic("Leaked socket fd %d: %s:%u -> %s:%u",
316cbe323513a0f20d1cf519fe9405e231d633e2Aki Tuomi first_fd, net_ip2addr(&addr), port,
316cbe323513a0f20d1cf519fe9405e231d633e2Aki Tuomi net_ip2addr(&raddr), rport);
316cbe323513a0f20d1cf519fe9405e231d633e2Aki Tuomi }
316cbe323513a0f20d1cf519fe9405e231d633e2Aki Tuomi
316cbe323513a0f20d1cf519fe9405e231d633e2Aki Tuomi if (fstat(first_fd, &st) == 0) {
316cbe323513a0f20d1cf519fe9405e231d633e2Aki Tuomi#ifdef __APPLE__
316cbe323513a0f20d1cf519fe9405e231d633e2Aki Tuomi /* OSX workaround: gettimeofday() calls shm_open()
316cbe323513a0f20d1cf519fe9405e231d633e2Aki Tuomi internally and the fd won't get closed on exec.
316cbe323513a0f20d1cf519fe9405e231d633e2Aki Tuomi We'll just skip all ino/dev=0 files and hope they
316cbe323513a0f20d1cf519fe9405e231d633e2Aki Tuomi weren't anything else. */
316cbe323513a0f20d1cf519fe9405e231d633e2Aki Tuomi if (st.st_ino == 0 && st.st_dev == 0)
316cbe323513a0f20d1cf519fe9405e231d633e2Aki Tuomi continue;
316cbe323513a0f20d1cf519fe9405e231d633e2Aki Tuomi#endif
316cbe323513a0f20d1cf519fe9405e231d633e2Aki Tuomi#ifdef HAVE_SYS_SYSMACROS_H
316cbe323513a0f20d1cf519fe9405e231d633e2Aki Tuomi i_panic("Leaked file fd %d: dev %s.%s inode %s",
316cbe323513a0f20d1cf519fe9405e231d633e2Aki Tuomi first_fd, dec2str(major(st.st_dev)),
316cbe323513a0f20d1cf519fe9405e231d633e2Aki Tuomi dec2str(minor(st.st_dev)), dec2str(st.st_ino));
316cbe323513a0f20d1cf519fe9405e231d633e2Aki Tuomi#else
316cbe323513a0f20d1cf519fe9405e231d633e2Aki Tuomi i_panic("Leaked file fd %d: dev %s inode %s",
316cbe323513a0f20d1cf519fe9405e231d633e2Aki Tuomi first_fd, dec2str(st.st_dev),
316cbe323513a0f20d1cf519fe9405e231d633e2Aki Tuomi dec2str(st.st_ino));
316cbe323513a0f20d1cf519fe9405e231d633e2Aki Tuomi#endif
316cbe323513a0f20d1cf519fe9405e231d633e2Aki Tuomi }
316cbe323513a0f20d1cf519fe9405e231d633e2Aki Tuomi
316cbe323513a0f20d1cf519fe9405e231d633e2Aki Tuomi i_panic("Leaked unknown fd %d (errno = %s)",
316cbe323513a0f20d1cf519fe9405e231d633e2Aki Tuomi first_fd, strerror(old_errno));
316cbe323513a0f20d1cf519fe9405e231d633e2Aki Tuomi }
316cbe323513a0f20d1cf519fe9405e231d633e2Aki Tuomi}
316cbe323513a0f20d1cf519fe9405e231d633e2Aki Tuomi