/* * Copyright (C) 2006-2007 Andre Noll * * Licensed under the GPL v2. For licencing details see COPYING. */ /** \file fd.c helper functions for file descriptor handling */ #include "para.h" #include #include #include #include "error.h" /** * check whether a file exists * * \param fn the file name * * \return Non-zero iff file exists. */ int file_exists(const char *fn) { struct stat statbuf; return !stat(fn, &statbuf); } /** * paraslash's wrapper for select(2) * * It calls select(2) (with no exceptfds) and starts over if select() was * interrupted by a signal. * * \param n the highest-numbered descriptor in any of the two sets, plus 1 * \param readfds fds that should be checked for readability * \param writefds fds that should be checked for writablility * \param timeout_tv upper bound on the amount of time elapsed before select() * returns * * \return The return value of the underlying select() call. * * All arguments are passed verbatim to select(2). * \sa select(2) select_tut(2) */ int para_select(int n, fd_set *readfds, fd_set *writefds, struct timeval *timeout_tv) { int ret, err; do { ret = select(n, readfds, writefds, NULL, timeout_tv); err = errno; } while (ret < 0 && err == EINTR); if (ret < 0) { PARA_CRIT_LOG("select error: %s, max_fileno: %d\n", strerror(err), n); ret = -E_SELECT; } return ret; } /** * set a file descriptor to non-blocking mode * * \param fd The file descriptor * * \returns 1 on success, -E_F_GETFL, -E_F_SETFL, on errors. */ int mark_fd_nonblock(int fd) { int flags = fcntl(fd, F_GETFL); if (flags < 0) return -E_F_GETFL; if (fcntl(fd, F_SETFL, ((long)flags) | O_NONBLOCK) < 0) return -E_F_SETFL; return 1; } /** * set a file descriptor in a fd_set * * \param fd the file descriptor to be set * \param fds the file descriptor set * \param max_fileno highest-numbered file descriptor * * This wrapper for FD_SET() passes its first two arguments to \p FD_SET. Upon * return, \a max_fileno contains the maximum of the old_value and \a fd. * * \sa para_select */ void para_fd_set(int fd, fd_set *fds, int *max_fileno) { if (fd < 0 || fd >= FD_SETSIZE) { PARA_EMERG_LOG("fatal: tried to add invalid fd %d\n", fd); exit(EXIT_FAILURE); } #if 0 { int flags = fcntl(fd, F_GETFL); if (!(flags & O_NONBLOCK)) { PARA_EMERG_LOG("fd %d is a blocking file descriptor\n", fd); exit(EXIT_FAILURE); } } #endif FD_SET(fd, fds); *max_fileno = PARA_MAX(*max_fileno, fd); } /** * paraslash's wrapper for fgets(3) * \param line pointer to the buffer to store the line * \param size the size of the buffer given by \a line * \param f the stream to read from * * \return Unlike the standard fgets() function, an integer value * is returned. On success, this function returns 1. On errors, -E_FGETS * is returned. A zero return value indicates an end of file condition. */ __must_check int para_fgets(char *line, int size, FILE *f) { again: if (fgets(line, size, f)) return 1; if (feof(f)) return 0; if (!ferror(f)) return -E_FGETS; if (errno != EINTR) { PARA_ERROR_LOG("%s\n", strerror(errno)); return -E_FGETS; } clearerr(f); goto again; } /** * *paraslash's wrapper for mmap * * \param length number of bytes to mmap * \param prot either PROT_NONE or the bitwise OR of one or more of * PROT_EXEC PROT_READ PROT_WRITE * \param flags exactly one of MAP_SHARED and MAP_PRIVATE * \param fd the file to mmap from * \param offset mmap start * * \return This function either returns a valid pointer to the mapped area * or calls exit() on errors. */ void *para_mmap(size_t length, int prot, int flags, int fd, off_t offset) { void *ret = mmap(NULL, length, prot, flags, fd, offset); if (ret != MAP_FAILED) return ret; PARA_EMERG_LOG("mmap failed: %s\n", strerror(errno)); PARA_EMERG_LOG("length: %zu, flags: %d, fd: %d, offset: %zu\n", length, flags, fd, (size_t)offset); exit(EXIT_FAILURE); }