d99d7de70156e19bf48d381c3576960e1c2045bb
[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/types.h>
12 #include <sys/wait.h>
13
14 static void err_exit(char *op, int errn)
15 {
16         fprintf(stderr, "%s: %s\n", op, strerror(errn));
17         exit(errn);
18 }
19
20 void *thread_fn(void *arg)
21 {
22         /* execve will release threads */
23         while(1) sleep(1);
24         return NULL;
25 }
26
27 struct flock fl = {
28         .l_type = F_WRLCK,
29         .l_whence = SEEK_SET,
30         .l_start = 0,
31         .l_len = 1,
32 };
33
34 static void checklock(int fd)
35 {
36         pid_t pid;
37
38         pid = fork();
39         if (pid < 0)
40                 err_exit("fork", errno);
41
42         if (!pid) {
43                 if (fcntl(fd, F_GETLK, &fl) < 0)
44                         err_exit("getlk", errno);
45                 if (fl.l_type == F_UNLCK) {
46                         printf("record lock is not preserved across execve(2)\n");
47                         exit(1);
48                 }
49                 exit(0);
50         }
51
52         waitpid(pid, NULL, 0);
53
54         exit(0);
55 }
56
57 int main(int argc, char **argv)
58 {
59         int fd, flags;
60         char fdstr[10];
61         char *newargv[] = { argv[0], argv[1], fdstr, NULL };
62         pthread_t th;
63
64         /* passing fd in argv[2] in execve */
65         if (argc == 3) {
66                 fd = atoi(argv[2]);
67                 checklock(fd);
68         }
69
70         fd = open(argv[1], O_WRONLY|O_CREAT, 0755);
71         if (fd < 0)
72                 err_exit("open", errno);
73         if (fcntl(fd, F_SETLK, &fl) < 0)
74                 err_exit("setlk", errno);
75
76         /* require multithread process to reproduce the issue */
77         pthread_create(&th, NULL, thread_fn, &fd);
78
79         if ((flags = fcntl(fd, F_GETFD)) < 0)
80                 err_exit("getfd", errno);
81         flags &= ~FD_CLOEXEC;
82         if (fcntl(fd, F_SETFD, flags) < 0)
83                 err_exit("setfd", errno);
84
85         snprintf(fdstr, sizeof(fdstr), "%d", fd);
86         execve(argv[0], newargv, NULL);
87
88         return 0;
89 }