forked from smerritt/flockit
-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathflockit.c
More file actions
116 lines (91 loc) · 2.69 KB
/
flockit.c
File metadata and controls
116 lines (91 loc) · 2.69 KB
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
#include <dlfcn.h>
#include <errno.h>
#include <gnu/lib-names.h> /* defines LIBC_SO */
#include <limits.h>
#include <stdatomic.h>
#include <stdarg.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/file.h>
#include <unistd.h>
/* Wrap libc's open() to add locking via flock().
If a file is opened for writing, we obtain an exclusive lock via
flock() on the whole file before returning the file descriptor.
If a file is opened only for reading, we obtain a shared lock.
This only applies if the environment variable FLOCKIT_FILE_PREFIX
is set, and it only applies to files whose names start with
FLOCKIT_FILE_PREFIX. Other files are unaffected. If
FLOCKIT_FILE_PREFIX is not set, no locking is done.
*/
typedef int (libc_open_t)(const char *, int, ...);
static _Atomic(libc_open_t*) libc_open;
void
flockit_setup(void) {
void *libc_handle;
if (!atomic_load_explicit(&libc_open, memory_order_relaxed)) {
void *tmp;
dlerror(); /* clear any existing error */
libc_handle = dlopen(LIBC_SO, RTLD_LAZY);
if (!libc_handle) {
fprintf(stderr, "flockit can't find libc: %s\n", dlerror());
exit(1);
}
tmp = dlsym(libc_handle, "open");
if (!tmp) {
fprintf(stderr, "flockit can't find fopen in libc: %s\n", dlerror());
exit(1);
}
atomic_store_explicit((_Atomic(void*)*)&libc_open, tmp, memory_order_relaxed);
dlclose(libc_handle);
dlerror(); /* clear any existing error */
}
}
static int open_inner(const char *file, int flags, mode_t mode) {
int fd, flock_operation;
char *flockit_file_prefix;
libc_open_t* open;
char pathbuf[PATH_MAX];
flockit_setup();
open = atomic_load_explicit(&libc_open, memory_order_relaxed);
if (flags & O_CREAT) {
fd = open(file, flags, mode);
} else {
fd = open(file, flags);
}
if (flags & O_WRONLY || flags & O_RDWR) {
flock_operation = LOCK_EX;
} else {
flock_operation = LOCK_SH;
}
flockit_file_prefix = getenv("FLOCKIT_FILE_PREFIX");
if (fd >= 0 && flockit_file_prefix) {
pathbuf[0] = 0;
if (!realpath(file, pathbuf)) {
strncpy(pathbuf, file, PATH_MAX);
pathbuf[PATH_MAX-1] = 0;
errno = 0;
}
if (!strncmp(pathbuf, flockit_file_prefix, strlen(flockit_file_prefix))) {
flock(fd, flock_operation);
}
}
return fd;
}
int
open(const char *file, int flags, ...) {
mode_t mode;
va_list argp;
va_start(argp, flags);
if (flags & O_CREAT) {
mode = va_arg(argp, mode_t);
} else {
mode = 0;
}
va_end(argp);
return open_inner(file, flags, mode);
}
int
creat(const char *file, mode_t mode) {
return open_inner(file, O_CREAT|O_WRONLY|O_TRUNC, mode);
}