1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
|
/* SPDX-License-Identifier: GPL-2.0 */
#include <stdio.h>
#include <unistd.h>
#include <assert.h>
#include <string.h>
#include <errno.h>
#include <sys/types.h>
#include <dirent.h>
#include <sys/stat.h>
#include <fcntl.h>
#include "gcc-compat.h"
#include "err.h"
#include "str.h"
#include "file.h"
/**
* Call a function for each subdirectory of the current working directory.
*
* \param dirname The directory to traverse.
* \param func The function to call for each subdirectory.
* \param private_data Pointer to an arbitrary data structure.
*
* For each top-level directory under \a dirname, the supplied function \a func is
* called. The full path of the subdirectory and the \a private_data pointer
* are passed to \a func.
*
* \return This function returns immediately if \a func returned a negative
* value. In this case \a func must set error_txt and this negative value is
* returned to the caller. Otherwise the function returns when all
* subdirectories have been passed to \a func.
*/
int for_each_subdir(int (*func)(const char *, void *), void *private_data)
{
struct dirent *entry;
int ret;
DIR *dir = opendir(".");
if (!dir)
return -ERRNO_TO_DSS_ERROR(errno);
while ((entry = readdir(dir))) {
mode_t m;
struct stat s;
if (!strcmp(entry->d_name, "."))
continue;
if (!strcmp(entry->d_name, ".."))
continue;
ret = lstat(entry->d_name, &s) == -1;
if (ret == -1) {
ret = -ERRNO_TO_DSS_ERROR(errno);
goto out;
}
m = s.st_mode;
if (!S_ISDIR(m))
continue;
ret = func(entry->d_name, private_data);
if (ret < 0)
goto out;
}
ret = 1;
out:
closedir(dir);
return ret;
}
/**
* Set a file descriptor to non-blocking mode.
*
* \param fd The file descriptor.
*
* \return Standard.
*/
__must_check int mark_fd_nonblocking(int fd)
{
int flags = fcntl(fd, F_GETFL);
if (flags < 0)
return -ERRNO_TO_DSS_ERROR(errno);
flags = fcntl(fd, F_SETFL, ((long)flags) | O_NONBLOCK);
if (flags < 0)
return -ERRNO_TO_DSS_ERROR(errno);
return 1;
}
/**
* dss' 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 on success, the
* negative system error code on errors.
*
* All arguments are passed verbatim to select(2).
* \sa select(2) select_tut(2).
*/
int dss_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)
return -ERRNO_TO_DSS_ERROR(errno);
return ret;
}
|