generic: test record locks across execve in multithread process
[xfstests-dev.git] / src / t_locks_execve.c
1 #ifndef _GNU_SOURCE
2 #define _GNU_SOURCE
3 #endif
4 #include <stdio.h>
5 #include <fcntl.h>
6 #include <stdlib.h>
7 #include <string.h>
8 #include <errno.h>
9 #include <pthread.h>
10 #include <unistd.h>
11 #include <sys/wait.h>
12
13 static void err_exit(char *op, int errn)
14 {
15         fprintf(stderr, "%s: %s\n", op, strerror(errn));
16         exit(errn);
17 }
18
19 void *thread_fn(void *arg)
20 {
21         /* execve will release threads */
22         while(1) sleep(1);
23         return NULL;
24 }
25
26 struct flock fl = {
27         .l_type = F_WRLCK,
28         .l_whence = SEEK_SET,
29         .l_start = 0,
30         .l_len = 1,
31 };
32
33 static void checklock(int fd)
34 {
35         if (fcntl(fd, F_GETLK, &fl) < 0)
36                 err_exit("getlk", errno);
37         if (fl.l_type == F_UNLCK) {
38                 printf("record lock is not preserved across execve(2)\n");
39                 exit(1);
40         }
41         exit(0);
42 }
43
44 int main(int argc, char **argv)
45 {
46         int fd, flags;
47         char fdstr[10];
48         char *newargv[] = { argv[0], argv[1], fdstr, NULL };
49         pthread_t th;
50
51         /* passing fd in argv[2] in execve */
52         if (argc == 3) {
53                 fd = atoi(argv[2]);
54                 checklock(fd);
55                 exit(0);
56         }
57
58         fd = open(argv[1], O_WRONLY|O_CREAT, 0755);
59         if (fd < 0)
60                 err_exit("open", errno);
61         if (fcntl(fd, F_SETLK, &fl) < 0)
62                 err_exit("setlk", errno);
63
64         /* require multithread process to reproduce the issue */
65         pthread_create(&th, NULL, thread_fn, &fd);
66
67         if ((flags = fcntl(fd, F_GETFD)) < 0)
68                 err_exit("getfd", errno);
69         flags &= ~FD_CLOEXEC;
70         if (fcntl(fd, F_SETFD, flags) < 0)
71                 err_exit("setfd", errno);
72
73         snprintf(fdstr, sizeof(fdstr), "%d", fd);
74         execve(argv[0], newargv, NULL);
75
76         return 0;
77 }