blob: 38a6eb79de3102939dd530d73819b00f80757f2f (
plain)
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
|
/* $OpenBSD: uthread_closefrom.c,v 1.4 2007/04/27 12:59:24 kurt Exp $ */
/* PUBLIC DOMAIN: No Rights Reserved. Marco S Hyman <marc@snafu.org> */
#include <sys/stat.h>
#include <errno.h>
#include <stdlib.h>
#include <pthread.h>
#include <unistd.h>
#include "pthread_private.h"
int
closefrom(int fd)
{
int ret = 0;
int safe_fd;
int lock_fd;
int *flags;
_thread_enter_cancellation_point();
if (fd < 0 || fd >= _thread_max_fdtsize) {
errno = EBADF;
ret = -1;
} else {
safe_fd = _thread_kern_pipe[0] > _thread_kern_pipe[1] ?
_thread_kern_pipe[0] : _thread_kern_pipe[1];
/*
* close individual files until we get past the pipe
* fds. Attempting to close a pipe fd is a no-op.
*/
for (safe_fd++; fd < safe_fd; fd++)
close(fd);
flags = calloc((size_t)_thread_max_fdtsize, sizeof *flags);
if (flags == NULL) {
/* use calloc errno */
ret = -1;
} else {
/* Lock and record all fd entries */
for (lock_fd = fd; lock_fd < _thread_max_fdtsize; lock_fd++) {
if (_thread_fd_table[lock_fd] != NULL &&
_thread_fd_table[lock_fd]->state != FD_ENTRY_CLOSED) {
ret = _FD_LOCK(lock_fd, FD_RDWR_CLOSE, NULL);
if (ret != -1)
flags[lock_fd] = 1;
else
break;
}
}
if (ret != -1) {
/*
* Close the entries and reset the non-bocking
* flag when needed.
*/
for (lock_fd = fd; lock_fd < _thread_max_fdtsize; lock_fd++) {
if (flags[lock_fd] != NULL) {
_thread_fd_entry_close(lock_fd);
}
}
/*
* Now let the system do its thing. It is not practical
* to try to prevent races with other threads that can
* create new file descriptors. We just have to assume
* the application is well behaved when using closefrom.
*/
ret = _thread_sys_closefrom(fd);
}
/*
* Unlock any locked entries.
*/
for (lock_fd = fd; lock_fd < _thread_max_fdtsize; lock_fd++) {
if (flags[lock_fd] != NULL) {
_FD_UNLOCK(lock_fd, FD_RDWR_CLOSE);
}
}
free(flags);
}
}
_thread_leave_cancellation_point();
return (ret);
}
|