11static void* unlock_thread(
void* argument) {
12 int* result = argument;
13 *result = fl_lock(*result, FL_CLASSIC, F_UNLCK, 0);
16static int process_lifetime(
void) {
17 int failed = 0, a = -1, b = -1, alias = -1, other = -1;
18 char path[128] = {0}, other_path[128] = {0};
20 CHECK((a = fl_file(path,
"/tmp")) >= 0 && (b = open(path, O_RDWR)) >= 0);
21 CHECK((other = fl_file(other_path,
"/tmp")) >= 0);
22 for (
int mode = 0; mode < 2; ++mode) {
23 CHECK((alias = open(path, O_RDWR)) >= 0);
24 CHECK(fl_lock(a, FL_CLASSIC, F_WRLCK, 0) == 0);
25 CHECK(fl_query(b, F_OFD_GETLK, 0, 1, F_WRLCK, 0, 0, getpid()) == 0);
27 CHECK(close(alias) == 0);
30 CHECK(dup2(other, alias) == alias);
32 CHECK(fl_query(b, F_OFD_GETLK, 0, 1, F_UNLCK, 0, 0, 0) == 0);
38 CHECK(fl_lock(a, FL_CLASSIC, F_WRLCK, 0) == 0);
39 int thread_result = a;
41 CHECK(pthread_create(&
worker, NULL, unlock_thread, &thread_result) == 0);
42 CHECK(pthread_join(
worker, NULL) == 0 && thread_result == 0);
43 CHECK(fl_query(b, F_OFD_GETLK, 0, 1, F_UNLCK, 0, 0, 0) == 0);
44 CHECK(fl_lock(a, FL_CLASSIC, F_WRLCK, 0) == 0);
45 const pid_t owner = getpid();
46 CHECK((child = fork()) >= 0);
49 if (fl_query(b, F_GETLK, 0, 1, F_WRLCK, 0, 0, owner) ||
50 fl_lock(a, FL_CLASSIC, F_WRLCK, 0) != -1 || errno != EAGAIN)
56 CHECK(fl_reap(child, 6000) == 0);
58 CHECK(fl_query(b, F_OFD_GETLK, 0, 1, F_WRLCK, 0, 0, owner) == 0);
79static int shared_fork(
int kind) {
80 int failed = 0, a = -1, b = -1, alias = -1, pair[2] = {-1, -1};
83 CHECK((a = fl_file(path,
"/tmp")) >= 0 && (b = open(path, O_RDWR)) >= 0);
84 CHECK(fl_lock(a, kind, F_WRLCK, 0) == 0 && (alias = dup(a)) >= 0);
87 CHECK(fl_lock(b, kind, F_WRLCK, 0) == -1 && errno == EAGAIN);
88 CHECK(socketpair(AF_UNIX, SOCK_STREAM, 0, pair) == 0 && (child = fork()) >= 0);
93 if (fl_lock(alias, kind, F_WRLCK, 0) || write(pair[1],
"h", 1) != 1 || fl_byte(pair[1],
'x'))
100 CHECK(fl_byte(pair[0],
'h') == 0);
101 CHECK(close(alias) == 0);
103 CHECK(fl_lock(b, kind, F_WRLCK, 0) == -1 && errno == EAGAIN);
104 CHECK(write(pair[0],
"x", 1) == 1 && fl_reap(child, 7000) == 0);
106 CHECK(fl_lock(b, kind, F_WRLCK, 0) == 0);
109 kill(child, SIGKILL);
110 fl_reap(child, 1000);
112 for (
int n = 0; n < 2; ++n)
126static int shared_rights(
int kind) {
127 int failed = 0, a = -1, b = -1, control[2] = {-1, -1}, transport[2] = {-1, -1};
129 char path[128] = {0};
130 CHECK((a = fl_file(path,
"/tmp")) >= 0 && (b = open(path, O_RDWR)) >= 0);
131 CHECK(fl_lock(a, kind, F_WRLCK, 0) == 0);
132 CHECK(socketpair(AF_UNIX, SOCK_STREAM, 0, control) == 0);
133 CHECK(socketpair(AF_UNIX, SOCK_STREAM, 0, transport) == 0 && (child = fork()) >= 0);
140 if (write(control[1],
"r", 1) != 1 || fl_byte(control[1],
'g'))
142 int received = fl_receive_fd(transport[1]);
143 if (received < 0 || fl_lock(received, kind, F_WRLCK, 0) || write(control[1],
"h", 1) != 1 ||
144 fl_byte(control[1],
'x'))
153 CHECK(fl_byte(control[0],
'r') == 0 && fl_send_fd(transport[0], a) == 0);
154 CHECK(close(a) == 0);
156 CHECK(fl_lock(b, kind, F_WRLCK, 0) == -1 && errno == EAGAIN);
157 CHECK(write(control[0],
"g", 1) == 1 && fl_byte(control[0],
'h') == 0);
158 CHECK(fl_lock(b, kind, F_WRLCK, 0) == -1 && errno == EAGAIN);
159 CHECK(write(control[0],
"x", 1) == 1 && fl_reap(child, 9000) == 0);
161 CHECK(fl_lock(b, kind, F_WRLCK, 0) == 0);
164 kill(child, SIGKILL);
165 fl_reap(child, 1000);
167 for (
int n = 0; n < 2; ++n) {
170 if (transport[n] >= 0)
182int file_lock_exec(
int argc,
char** argv) {
186 const int fd = atoi(argv[2]), socket = atoi(argv[3]), closed = atoi(argv[4]);
187 const int result = fcntl(fd, F_GETFD, 0);
188 if (closed ? result != -1 || errno != EBADF : result < 0)
190 return write(socket,
"e", 1) == 1 && fl_byte(socket,
'x') == 0 ? 0 : 22;
192static int exec_lifetime(
int kind,
int cloexec) {
193 int failed = 0, a = -1, probe = -1, pair[2] = {-1, -1};
195 char path[128] = {0};
196 CHECK((a = fl_file(path,
"/tmp")) >= 0 && (probe = open(path, O_RDWR)) >= 0);
197 CHECK(socketpair(AF_UNIX, SOCK_STREAM, 0, pair) == 0 && (child = fork()) >= 0);
202 if (cloexec == 2 && open(path, O_RDONLY | O_CLOEXEC) < 0)
204 if (fl_lock(a, kind, F_WRLCK, 0) || fcntl(a, F_SETFD, cloexec == 1 ? FD_CLOEXEC : 0))
206 char descriptor[20], socket[20], flag[4];
207 snprintf(descriptor,
sizeof(descriptor),
"%d", a);
208 snprintf(socket,
sizeof(socket),
"%d", pair[1]);
209 snprintf(flag,
sizeof(flag),
"%d", cloexec == 1);
210 execl(LOCK_APP, LOCK_APP,
"lock-exec", descriptor, socket, flag, (
char*)NULL);
217 CHECK(fl_byte(pair[0],
'e') == 0);
219 CHECK(fl_lock(probe, kind, F_WRLCK, 0) == 0);
221 CHECK(fl_lock(probe, kind, F_WRLCK, 0) == -1 && errno == EAGAIN);
222 CHECK(write(pair[0],
"x", 1) == 1 && fl_reap(child, 7000) == 0);
224 CHECK(fl_lock(probe, kind, F_WRLCK, 0) == 0);
227 kill(child, SIGKILL);
228 fl_reap(child, 1000);
230 for (
int n = 0; n < 2; ++n)
242static int inode_aliases(
void) {
243 int failed = 0, a = -1, b = -1, c = -1;
244 char path[128] = {0}, linked[160] = {0}, renamed[160] = {0};
245 struct stat first, second;
247 puts(
"FILE-LOCK-CONTRACT: SKIP disk hard-link fixture requires root");
250 CHECK((a = fl_file(path,
"")) >= 0);
251 snprintf(linked,
sizeof(linked),
"%s.link", path);
252 snprintf(renamed,
sizeof(renamed),
"%s.renamed", path);
253 CHECK(link(path, linked) == 0 && (b = open(linked, O_RDWR)) >= 0);
254 CHECK(fstat(a, &first) == 0 && fstat(b, &second) == 0 && first.st_dev == second.st_dev &&
255 first.st_ino == second.st_ino);
256 CHECK(fl_lock(a, FL_OFD, F_WRLCK, 0) == 0);
257 CHECK(fl_lock(b, FL_OFD, F_WRLCK, 0) == -1 && errno == EAGAIN);
258 CHECK(rename(path, renamed) == 0 && unlink(linked) == 0);
259 CHECK((c = open(renamed, O_RDWR)) >= 0 && unlink(renamed) == 0);
260 CHECK(fl_query(c, F_GETLK, 0, 1, F_WRLCK, 0, 0, -1) == 0);
261 CHECK(fl_lock(a, FL_OFD, F_UNLCK, 0) == 0);
262 CHECK(fl_lock(a, FL_CLASSIC, F_WRLCK, 0) == 0);
263 CHECK(close(b) == 0);
265 CHECK(fl_query(c, F_OFD_GETLK, 0, 1, F_UNLCK, 0, 0, 0) == 0);
266 CHECK(fl_lock(a, FL_FLOCK, F_WRLCK, 0) == 0);
267 CHECK(fl_lock(c, FL_FLOCK, F_WRLCK, 0) == -1 && errno == EAGAIN);
268 CHECK(close(a) == 0);
270 CHECK(fl_lock(c, FL_FLOCK, F_WRLCK, 0) == 0);
286int file_lock_lifetime(
void) {
287 if (process_lifetime() || exec_lifetime(FL_CLASSIC, 2))
289 for (
int kind = 0; kind < 3; ++kind) {
290 if (kind != FL_CLASSIC && (shared_fork(kind) || shared_rights(kind)))
292 if (exec_lifetime(kind, 0) || exec_lifetime(kind, 1))
295 return inode_aliases();