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