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