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