1 /* $OpenBSD: uthread_closefrom.c,v 1.1 2004/01/15 22:22:11 marc Exp $ */
2 
3 /* PUBLIC DOMAIN: No Rights Reserved. Marco S Hyman <marc@snafu.org> */
4 
5 #include <sys/stat.h>
6 
7 #include <errno.h>
8 #include <fcntl.h>
9 #include <pthread.h>
10 #include <unistd.h>
11 
12 #include "pthread_private.h"
13 
14 /*
15  * Reset the non-blocking flag if necessary.   Remove the fd table entry
16  * for the given fd.
17  */
18 static void
_close_flags(int fd)19 _close_flags(int fd)
20 {
21 	struct stat sb;
22 	int flags;
23 
24 	if (_FD_LOCK(fd, FD_RDWR, NULL) == 0) {
25 		if ((_thread_sys_fstat(fd, &sb) == 0) &&
26 		    ((S_ISREG(sb.st_mode) || S_ISCHR(sb.st_mode)) &&
27 		     (_thread_fd_table[fd]->flags & O_NONBLOCK) == 0)) {
28 			/* Get the current flags: */
29 			flags = _thread_sys_fcntl(fd, F_GETFL, NULL);
30 			/* Clear the nonblocking file descriptor flag: */
31 			_thread_sys_fcntl(fd, F_SETFL, flags & ~O_NONBLOCK);
32 		}
33 		_thread_fd_table_remove(fd);
34 	}
35 }
36 
37 int
closefrom(int fd)38 closefrom(int fd)
39 {
40 	int ret;
41 	int safe_fd;
42 	int lock_fd;
43 
44 	_thread_enter_cancellation_point();
45 
46 	if (fd < 0 || fd >= _thread_dtablesize) {
47 		errno = EBADF;
48 		ret = -1;
49 	} else {
50 		safe_fd = _thread_kern_pipe[0] > _thread_kern_pipe[1] ?
51 			_thread_kern_pipe[0] : _thread_kern_pipe[1];
52 
53 		/*
54 		 * close individual files until we get past the pipe
55 		 * fds.  Attempting to close a pipe fd is a no-op.
56 		 */
57 		for (safe_fd++; fd < safe_fd; fd++)
58 			close(fd);
59 
60 		/* Reset flags and clean up the fd table for fds to close */
61 		for (lock_fd = fd; lock_fd < _thread_dtablesize; lock_fd++)
62 			if (_thread_fd_table[lock_fd] != NULL)
63 				_close_flags(lock_fd);
64 
65 		/* Now let the system do its thing */
66 		ret = _thread_sys_closefrom(fd);
67 	}
68 
69 	_thread_leave_cancellation_point();
70 
71 	return ret;
72 
73 }
74