/* * Copyright (C) 2008-2015 Tobias Brunner * Copyright (C) 2005-2008 Martin Willi * Hochschule fuer Technik Rapperswil * * 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 2 of the License, or (at your * option) any later version. See . * * 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. */ #include "utils.h" #include #include #include #include #include #ifndef WIN32 # include #endif #ifndef HAVE_CLOSEFROM #if defined(__linux__) && defined(HAVE_SYS_SYSCALL_H) # include # include # include /* This is from the kernel sources. We limit the length of directory names to * 256 as we only use it to enumerate FDs. */ struct linux_dirent64 { u_int64_t d_ino; int64_t d_off; unsigned short d_reclen; unsigned char d_type; char d_name[256]; }; #else /* !defined(__linux__) || !defined(HAVE_SYS_SYSCALL_H) */ # include #endif /* defined(__linux__) && defined(HAVE_SYS_SYSCALL_H) */ #endif #include #include #define FD_DIR "/proc/self/fd" #ifdef WIN32 #include #include /** * Flag to indicate signaled wait_sigint() */ static bool sigint_signaled = FALSE; /** * Condvar to wait in wait_sigint() */ static condvar_t *sigint_cond; /** * Mutex to check signaling() */ static mutex_t *sigint_mutex; /** * Control handler to catch ^C */ static BOOL WINAPI handler(DWORD dwCtrlType) { switch (dwCtrlType) { case CTRL_C_EVENT: case CTRL_BREAK_EVENT: case CTRL_CLOSE_EVENT: sigint_mutex->lock(sigint_mutex); sigint_signaled = TRUE; sigint_cond->signal(sigint_cond); sigint_mutex->unlock(sigint_mutex); return TRUE; default: return FALSE; } } /** * Windows variant */ void wait_sigint() { SetConsoleCtrlHandler(handler, TRUE); sigint_mutex = mutex_create(MUTEX_TYPE_DEFAULT); sigint_cond = condvar_create(CONDVAR_TYPE_DEFAULT); sigint_mutex->lock(sigint_mutex); while (!sigint_signaled) { sigint_cond->wait(sigint_cond, sigint_mutex); } sigint_mutex->unlock(sigint_mutex); sigint_mutex->destroy(sigint_mutex); sigint_cond->destroy(sigint_cond); } #else /* !WIN32 */ /** * Unix variant */ void wait_sigint() { sigset_t set; sigemptyset(&set); sigaddset(&set, SIGINT); sigaddset(&set, SIGTERM); sigprocmask(SIG_BLOCK, &set, NULL); while (sigwaitinfo(&set, NULL) == -1 && errno == EINTR) { /* wait for signal */ } } #ifndef HAVE_SIGWAITINFO int sigwaitinfo(const sigset_t *set, void *info) { int sig, err; if (info) { /* we don't replicate siginfo_t, fail if anybody tries to use it */ errno = EINVAL; return -1; } err = sigwait(set, &sig); if (err != 0) { errno = err; sig = -1; } return sig; } #endif /* HAVE_SIGWAITINFO */ #endif /* WIN32 */ #ifndef HAVE_CLOSEFROM /** * Described in header. */ void closefrom(int low_fd) { int max_fd, dir_fd, fd; /* try to close only open file descriptors on Linux... */ #if defined(__linux__) && defined(HAVE_SYS_SYSCALL_H) /* By directly using a syscall we avoid any calls that might be unsafe after * fork() (e.g. malloc()). */ char buffer[sizeof(struct linux_dirent64)]; struct linux_dirent64 *entry; int offset, len; dir_fd = open("/proc/self/fd", O_RDONLY); if (dir_fd != -1) { while ((len = syscall(__NR_getdents64, dir_fd, buffer, sizeof(buffer))) > 0) { for (offset = 0; offset < len; offset += entry->d_reclen) { entry = (struct linux_dirent64*)(buffer + offset); if (!isdigit(entry->d_name[0])) { continue; } fd = atoi(entry->d_name); if (fd != dir_fd && fd >= low_fd) { close(fd); } } } close(dir_fd); return; } #else /* !defined(__linux__) || !defined(HAVE_SYS_SYSCALL_H) */ /* This is potentially unsafe when called after fork() in multi-threaded * applications. In particular opendir() will require an allocation. * Depends on how the malloc() implementation handles such situations. */ DIR *dir; struct dirent *entry; #ifndef HAVE_DIRFD /* if we don't have dirfd() lets close the lowest FD and hope it gets reused * by opendir() */ close(low_fd); dir_fd = low_fd++; #endif dir = opendir(FD_DIR); if (dir) { #ifdef HAVE_DIRFD dir_fd = dirfd(dir); #endif while ((entry = readdir(dir))) { if (!isdigit(entry->d_name[0])) { continue; } fd = atoi(entry->d_name); if (fd != dir_fd && fd >= low_fd) { close(fd); } } closedir(dir); return; } #endif /* defined(__linux__) && defined(HAVE_SYS_SYSCALL_H) */ /* ...fall back to closing all fds otherwise */ #ifdef WIN32 max_fd = _getmaxstdio(); #else max_fd = (int)sysconf(_SC_OPEN_MAX); #endif if (max_fd < 0) { max_fd = 256; } for (fd = low_fd; fd < max_fd; fd++) { close(fd); } } #endif /* HAVE_CLOSEFROM */ /** * return null */ void *return_null() { return NULL; } /** * returns TRUE */ bool return_true() { return TRUE; } /** * returns FALSE */ bool return_false() { return FALSE; } /** * nop operation */ void nop() { } /** * See header */ void utils_init() { #ifdef WIN32 windows_init(); #endif atomics_init(); strerror_init(); } /** * See header */ void utils_deinit() { #ifdef WIN32 windows_deinit(); #endif atomics_deinit(); strerror_deinit(); }