1 #include "headers.h"
2 #include <stdarg.h>
3 #include "wrap_oclose.h"
4 
5 pthread_mutex_t fd_pool_mutex;	/* This must always be visible */
6 
7 #ifndef	HAVE_WEAK_OPEN
8 #ifdef	PSRC_bpf
9 #warning Your platform does not have open() as a weak alias for _open() the standard C library.
10 #warning Practically this means that in order for ipcad to work chroot()ed
11 #warning in presence of interfaces that are not configured when the ipcad starts up,
12 #warning you would need to create dev/bpf* devices under the chroot directory.
13 #warning If you did not understand this, you are probably fine.
14 #endif	/* PSRC_bpf */
15 #else	/* HAVE_WEAK_OPEN */
16 
17 /*
18  * Real open()/close() defined as weak aliases for _open()/_close().
19  * These are their prototypes.
20  */
21 int _open(const char *path, int flags, ...);
22 int _close(int d);
23 
24 /*
25  * This pool is established to reuse /dev/bpfX file descriptors in case
26  * chroot() makes /dev/bpf* devices unavailable.
27  */
28 #define	FD_USED_SIZE	16384
29 typedef struct bpf_fd_s {
30 	int fd;
31 	struct bpf_fd_s *next;
32 } bpf_fd_t;
33 static bpf_fd_t *fds_pool_head;	/* File descriptors cache */
34 static bpf_fd_t *fds_used[FD_USED_SIZE];	/* Currently being used */
35 
36 int
open(const char * path,int flags,...)37 open(const char *path, int flags, ...) {
38 	int special;
39 	int d;
40 
41 	if(flags & O_CREAT) {
42 		va_list ap;
43 		mode_t mode;
44 		va_start(ap, flags);
45 		mode = va_arg(ap, int);
46 		va_end(ap);
47 		return _open(path, flags, mode);
48 	}
49 
50 	/*
51 	 * Enable file descriptors caching (special treatment mode)
52 	 * if path contains known pattern.
53 	 */
54 	special = (path && strncmp(path, "/dev/bpf", 8) == 0)?1:0;
55 
56 	if(special) {
57 		pthread_mutex_lock(&fd_pool_mutex);
58 		if(fds_pool_head) {
59 			bpf_fd_t *bfd = fds_pool_head;
60 			fds_pool_head = bfd->next;
61 			bfd->next = 0;
62 			assert(fds_used[bfd->fd] == NULL);
63 			fds_used[bfd->fd] = bfd;
64 			pthread_mutex_unlock(&fd_pool_mutex);
65 			return bfd->fd;	/* Use cached copy */
66 		}
67 		pthread_mutex_unlock(&fd_pool_mutex);
68 	}
69 
70 	d = _open(path, flags);
71 	if(d == -1)
72 		return -1;
73 
74 	if(special && d >= 0 && d < FD_USED_SIZE) {
75 		bpf_fd_t *bfd = malloc(sizeof(*bfd));
76 		if(bfd == NULL) {
77 			close(d);
78 			errno = EPERM;	/* Simulate real problem */
79 			return -1;
80 		}
81 		bfd->fd = d;
82 		bfd->next = 0;
83 		assert(fds_used[d] == NULL);
84 		fds_used[d] = bfd;	/* Lock-free is OK */
85 	}
86 
87 	return d;
88 }
89 
90 int
close(int d)91 close(int d) {
92 	if(d >= 0 && d < FD_USED_SIZE) {
93 		pthread_mutex_lock(&fd_pool_mutex);
94 		if(fds_used[d]) {
95 			/*
96 			 * Instead of closing, put back into the pool.
97 			 */
98 			fds_used[d]->next = fds_pool_head;
99 			fds_pool_head = fds_used[d];
100 			fds_used[d] = NULL;
101 			pthread_mutex_unlock(&fd_pool_mutex);
102 			return 0;
103 		}
104 		pthread_mutex_unlock(&fd_pool_mutex);
105 	}
106 	return _close(d);
107 }
108 
109 #endif	/* HAVE_WEAK_OPEN */
110