1/** Test program for POSIX advisory record locking. See also #164669
2 *  (http://bugs.kde.org/show_bug.cgi?id=164669).
3 *  See also http://www.opengroup.org/onlinepubs/007908799/xsh/fcntl.html.
4 */
5
6
7#include <assert.h>
8#include <errno.h>
9#include <fcntl.h>
10#include <stdio.h>
11#include <stdlib.h>
12#include "tests/sys_mman.h"
13#include <sys/stat.h>
14#include <sys/types.h>
15#include <sys/wait.h>
16#include <unistd.h>
17#include <unistd.h>
18
19
20/** Lock an entire file exclusively.
21 *
22 *  @return 1 upon success, 0 upon failure.
23 */
24static int lock_file(const int fd)
25{
26  struct flock fl;
27
28  fl.l_type   = F_WRLCK;  /* exclusive lock */
29  fl.l_whence = SEEK_SET;
30  fl.l_start  = 0;
31  fl.l_len    = 0;        /* lock entire file */
32  fl.l_pid    = 0;
33  return fcntl(fd, F_SETLK, &fl) >= 0;
34}
35
36static int open_lock_and_map(const char* const process_name,
37                             const char* const filename)
38{
39  int fd;
40  int flags;
41
42  fd = open(filename, O_RDWR | O_CREAT, S_IRUSR | S_IWUSR);
43  if (fd < 0)
44  {
45    perror("open");
46    goto err1;
47  }
48
49  flags = fcntl(fd, F_GETFD);
50  assert(flags >= 0);
51  if (fcntl(fd, F_SETFD, flags | FD_CLOEXEC) < 0)
52    assert(0);
53
54  fprintf(stderr, "%s: about to lock file for writing.\n", process_name);
55  if (! lock_file(fd))
56  {
57    perror("fcntl");
58    goto err2;
59  }
60
61  fprintf(stderr, "%s: file locking attempt succeeded.\n", process_name);
62  if (mmap(NULL, 1, PROT_WRITE, MAP_SHARED, fd, 0) == 0)
63  {
64    perror("mmap");
65    goto err2;
66  }
67
68  goto out;
69
70err2:
71  close(fd);
72err1:
73out:
74  return fd;
75}
76
77int main(int argc, char *argv[])
78{
79  int fd1;
80  int fd2;
81  int exitcode = 1;
82  char filename[256];
83
84  snprintf(filename, sizeof(filename), "/tmp/valgrind-file-locking-test.%d",
85           getpid());
86
87  unlink(filename);
88
89  if ((fd1 = open_lock_and_map("parent", filename)) >= 0)
90  {
91    pid_t fork_result;
92
93    fork_result = fork();
94    switch (fork_result)
95    {
96    case -1:
97      perror("fork");
98      break;
99
100    case 0:
101      /* child */
102      fd2 = open_lock_and_map("child", filename);
103      if (fd2 >= 0)
104      {
105        close(fd2);
106      }
107      exit(0);
108      break;
109
110    default:
111      /* parent */
112      {
113        int child_status;
114        int wait_result;
115
116        wait_result = wait4(fork_result, &child_status, 0, 0);
117        assert(wait_result >= 0);
118      }
119    }
120  }
121
122  close(fd1);
123
124  unlink(filename);
125
126  fprintf(stderr, "Test finished.\n");
127
128  return exitcode;
129}
130