aboutsummaryrefslogtreecommitdiff
path: root/memcheck/tests/file_locking.c
blob: 35f2995e17a742173ed8bce2e50589a10db68d0c (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
/** Test program for POSIX advisory record locking. See also #164669
 *  (http://bugs.kde.org/show_bug.cgi?id=164669).
 *  See also http://www.opengroup.org/onlinepubs/007908799/xsh/fcntl.html.
 */


#include <assert.h>
#include <errno.h>
#include <fcntl.h>
#include <stdio.h>
#include <stdlib.h>
#include "tests/sys_mman.h"
#include <sys/stat.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <unistd.h>
#include <unistd.h>


/** Lock an entire file exclusively.
 *
 *  @return 1 upon success, 0 upon failure.
 */
static int lock_file(const int fd)
{
  struct flock fl;

  fl.l_type   = F_WRLCK;  /* exclusive lock */
  fl.l_whence = SEEK_SET;
  fl.l_start  = 0;
  fl.l_len    = 0;        /* lock entire file */
  fl.l_pid    = 0;
  return fcntl(fd, F_SETLK, &fl) >= 0;
}

static int open_lock_and_map(const char* const process_name,
                             const char* const filename)
{
  int fd;
  int flags;

  fd = open(filename, O_RDWR | O_CREAT, S_IRUSR | S_IWUSR);
  if (fd < 0)
  {
    perror("open");
    goto err1;
  }

  flags = fcntl(fd, F_GETFD);
  assert(flags >= 0);
  if (fcntl(fd, F_SETFD, flags | FD_CLOEXEC) < 0)
    assert(0);

  fprintf(stderr, "%s: about to lock file for writing.\n", process_name);
  if (! lock_file(fd))
  {
    perror("fcntl");
    goto err2;
  }

  fprintf(stderr, "%s: file locking attempt succeeded.\n", process_name);
  if (mmap(NULL, 1, PROT_WRITE, MAP_SHARED, fd, 0) == 0)
  {
    perror("mmap");
    goto err2;
  }

  goto out;

err2:
  close(fd);
err1:
out:
  return fd;
}

int main(int argc, char *argv[]) 
{
  int fd1;
  int fd2;
  int exitcode = 1;
  char filename[256];

  snprintf(filename, sizeof(filename), "/tmp/valgrind-file-locking-test.%ld",
           (long) getpid());

  unlink(filename);

  if ((fd1 = open_lock_and_map("parent", filename)) >= 0)
  {
    pid_t fork_result;

    fork_result = fork();
    switch (fork_result)
    {
    case -1:
      perror("fork");
      break;

    case 0:
      /* child */
      fd2 = open_lock_and_map("child", filename);
      if (fd2 >= 0)
      {
        close(fd2);
      }
      exit(0);
      break;

    default:
      /* parent */
      {
        int child_status;
        int wait_result;

        wait_result = wait4(fork_result, &child_status, 0, 0);
        assert(wait_result >= 0);
      }
    }
  }

  close(fd1);

  unlink(filename);

  fprintf(stderr, "Test finished.\n");

  return exitcode;
}