Fix typo in documentation of --logfile.
[dss.git] / file.c
1 /*
2 * Copyright (C) 2006-2010 Andre Noll <maan@tuebingen.mpg.de>
3 *
4 * Licensed under the GPL v2. For licencing details see COPYING.
5 */
6
7 #include <stdio.h>
8 #include <unistd.h>
9 #include <assert.h>
10 #include <string.h>
11 #include <errno.h>
12 #include <sys/types.h>
13 #include <dirent.h>
14 #include <sys/stat.h>
15 #include <fcntl.h>
16
17 #include "gcc-compat.h"
18 #include "err.h"
19 #include "str.h"
20 #include "file.h"
21
22 /**
23 * Call a function for each subdirectory of the current working directory.
24 *
25 * \param dirname The directory to traverse.
26 * \param func The function to call for each subdirecrtory.
27 * \param private_data Pointer to an arbitrary data structure.
28 *
29 * For each top-level directory under \a dirname, the supplied function \a func is
30 * called. The full path of the subdirectory and the \a private_data pointer
31 * are passed to \a func.
32 *
33 * \return This function returns immediately if \a func returned a negative
34 * value. In this case \a func must set error_txt and this negative value is
35 * returned to the caller. Otherwise the function returns when all
36 * subdirectories have been passed to \a func.
37 */
38
39 int for_each_subdir(int (*func)(const char *, void *), void *private_data)
40 {
41 struct dirent *entry;
42 int ret;
43 DIR *dir = opendir(".");
44
45 if (!dir)
46 return -ERRNO_TO_DSS_ERROR(errno);
47 while ((entry = readdir(dir))) {
48 mode_t m;
49 struct stat s;
50
51 if (!strcmp(entry->d_name, "."))
52 continue;
53 if (!strcmp(entry->d_name, ".."))
54 continue;
55 ret = lstat(entry->d_name, &s) == -1;
56 if (ret == -1) {
57 ret = -ERRNO_TO_DSS_ERROR(errno);
58 goto out;
59 }
60 m = s.st_mode;
61 if (!S_ISDIR(m))
62 continue;
63 ret = func(entry->d_name, private_data);
64 if (ret < 0)
65 goto out;
66 }
67 ret = 1;
68 out:
69 closedir(dir);
70 return ret;
71 }
72 /**
73 * Wrapper for chdir(2).
74 *
75 * \param path The specified directory.
76 *
77 * \return Standard.
78 */
79 int dss_chdir(const char *path)
80 {
81 if (chdir(path) >= 0)
82 return 1;
83 return -ERRNO_TO_DSS_ERROR(errno);
84 }
85
86 /**
87 * Set a file descriptor to non-blocking mode.
88 *
89 * \param fd The file descriptor.
90 *
91 * \return Standard.
92 */
93 __must_check int mark_fd_nonblocking(int fd)
94 {
95 int flags = fcntl(fd, F_GETFL);
96 if (flags < 0)
97 return -ERRNO_TO_DSS_ERROR(errno);
98 flags = fcntl(fd, F_SETFL, ((long)flags) | O_NONBLOCK);
99 if (flags < 0)
100 return -ERRNO_TO_DSS_ERROR(errno);
101 return 1;
102 }
103
104 /**
105 * dss' wrapper for select(2).
106 *
107 * It calls select(2) (with no exceptfds) and starts over if select() was
108 * interrupted by a signal.
109 *
110 * \param n The highest-numbered descriptor in any of the two sets, plus 1.
111 * \param readfds fds that should be checked for readability.
112 * \param writefds fds that should be checked for writablility.
113 * \param timeout_tv upper bound on the amount of time elapsed before select()
114 * returns.
115 *
116 * \return The return value of the underlying select() call on success, the
117 * negative system error code on errors.
118 *
119 * All arguments are passed verbatim to select(2).
120 * \sa select(2) select_tut(2).
121 */
122 int dss_select(int n, fd_set *readfds, fd_set *writefds,
123 struct timeval *timeout_tv)
124 {
125 int ret, err;
126 do {
127 ret = select(n, readfds, writefds, NULL, timeout_tv);
128 err = errno;
129 } while (ret < 0 && err == EINTR);
130 if (ret < 0)
131 return -ERRNO_TO_DSS_ERROR(errno);
132 return ret;
133 }