Change year of copyright from 2008 to 2009.
[paraslash.git] / fd.c
diff --git a/fd.c b/fd.c
index 83c6cd5b4d39c77f723aef5f67553b60d6653a31..6042a58f531af44e941f012fdc273d78c2f9fb37 100644 (file)
--- a/fd.c
+++ b/fd.c
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2006-2007 Andre Noll <maan@systemlinux.org>
+ * Copyright (C) 2006-2009 Andre Noll <maan@systemlinux.org>
  *
  * Licensed under the GPL v2. For licencing details see COPYING.
  */
 #include "para.h"
 #include "error.h"
 
+/**
+ * Write a buffer to a file descriptor, re-write on short writes.
+ *
+ * \param fd The file descriptor.
+ * \param buf The buffer to be sent.
+ * \param len The length of \a buf.
+ *
+ * \return Standard. In any case, the number of bytes that have been written is
+ * stored in \a len.
+ */
+int write_all(int fd, const char *buf, size_t *len)
+{
+       size_t total = *len;
+
+       assert(total);
+       *len = 0;
+       while (*len < total) {
+               int ret = write(fd, buf + *len, total - *len);
+               if (ret == -1)
+                       return -ERRNO_TO_PARA_ERROR(errno);
+               *len += ret;
+       }
+       return 1;
+}
+
 /**
  * Check whether a file exists.
  *
@@ -60,6 +85,24 @@ int para_select(int n, fd_set *readfds, fd_set *writefds,
        return ret;
 }
 
+/**
+ * Set a file descriptor to blocking mode.
+ *
+ * \param fd The file descriptor.
+ *
+ * \return Standard.
+ */
+__must_check int mark_fd_blocking(int fd)
+{
+       int flags = fcntl(fd, F_GETFL);
+       if (flags < 0)
+               return -ERRNO_TO_PARA_ERROR(errno);
+       flags = fcntl(fd, F_SETFL, ((long)flags) & ~O_NONBLOCK);
+       if (flags < 0)
+               return -ERRNO_TO_PARA_ERROR(errno);
+       return 1;
+}
+
 /**
  * Set a file descriptor to non-blocking mode.
  *
@@ -67,7 +110,7 @@ int para_select(int n, fd_set *readfds, fd_set *writefds,
  *
  * \return Standard.
  */
-int mark_fd_nonblock(int fd)
+__must_check int mark_fd_nonblocking(int fd)
 {
        int flags = fcntl(fd, F_GETFL);
        if (flags < 0)
@@ -111,16 +154,16 @@ void para_fd_set(int fd, fd_set *fds, int *max_fileno)
 }
 
 /**
-* 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.
-*/
+ * 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:
@@ -242,9 +285,10 @@ int para_opendir(const char *dirname, DIR **dir, int *cwd)
        if (*dir)
                return 1;
        ret = -ERRNO_TO_PARA_ERROR(errno);
-/* Ignore return value of fchdir() and close(). We're busted anyway. */
-       if (cwd)
-               fchdir(*cwd);
+       /* Ignore return value of fchdir() and close(). We're busted anyway. */
+       if (cwd) {
+               int __a_unused ret2 = fchdir(*cwd); /* STFU, gcc */
+       }
 close_cwd:
        if (cwd)
                close(*cwd);
@@ -281,14 +325,19 @@ int para_mkdir(const char *path, mode_t mode)
 }
 
 /**
- * Map a file into memory.
+ * Open a file and map it into memory.
  *
  * \param path Name of the regular file to map.
  * \param open_mode Either \p O_RDONLY or \p O_RDWR.
- * \param obj On success, the mapping is returned here.
+ * \param map On success, the mapping is returned here.
+ * \param size size of the mapping.
+ * \param fd_ptr The file descriptor of the mapping.
  *
- * \return Positive on success, negative on errors. Possible errors include: \p
- * E_FSTAT, any errors returned by para_open(), \p E_EMPTY, \p E_MMAP.
+ * If \a fd_ptr is \p NULL, the file descriptor resulting from the underlying
+ * open call is closed after mmap().  Otherwise the file is kept open and the
+ * file descriptor is returned in \a fd_ptr.
+ *
+ * \return Standard.
  *
  * \sa para_open(), mmap(2).
  */
@@ -332,3 +381,70 @@ out:
                *fd_ptr = fd;
        return ret;
 }
+
+/**
+ * A wrapper for munmap(2).
+ *
+ * \param start The start address of the memory mapping.
+ * \param length The size of the mapping.
+ *
+ * \return Positive on success, \p -E_MUNMAP on errors.
+ *
+ * \sa munmap(2), mmap_full_file().
+ */
+int para_munmap(void *start, size_t length)
+{
+       int err;
+       if (munmap(start, length) >= 0)
+               return 1;
+       err = errno;
+       PARA_ERROR_LOG("munmap (%p/%zu) failed: %s\n", start, length,
+               strerror(err));
+       return -ERRNO_TO_PARA_ERROR(err);
+}
+
+/**
+ * Check a file descriptor for writability.
+ *
+ * \param fd The file descriptor.
+ *
+ * \return positive if fd is ready for writing, zero if it isn't, negative if
+ * an error occurred.
+ */
+
+int write_ok(int fd)
+{
+       struct timeval tv = {0, 0};
+       fd_set wfds;
+       int ret;
+again:
+       FD_ZERO(&wfds);
+       FD_SET(fd, &wfds);
+       tv.tv_sec = 0;
+       tv.tv_usec = 0;
+       ret = select(fd + 1, NULL, &wfds, NULL, &tv);
+       if (ret < 0 && errno == EINTR)
+               goto again;
+       return ret;
+}
+
+/**
+ * Ensure that file descriptors 0, 1, and 2 are valid.
+ *
+ * Common approach that opens /dev/null until it gets a file descriptor greater
+ * than two.
+ *
+ * \sa okir's Black Hats Manual.
+ */
+void valid_fd_012(void)
+{
+       while (1) {
+               int fd = open("/dev/null", O_RDWR);
+               if (fd < 0)
+                       exit(EXIT_FAILURE);
+               if (fd > 2) {
+                       close(fd);
+                       break;
+               }
+       }
+}