1b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov
2b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov/* Test program to demonstrate valgrind breaking fcntl locks during
3b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov * mmap.  Feed it a r/w file, such as its own source code. */
4b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov
5b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov/* See bug 280965. */
6b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov
7b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov#include <stdio.h>
8b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov#include <stdlib.h>
9b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov#include <unistd.h>
10b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov#include <fcntl.h>
11b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov#include <sys/mman.h>
12b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov#include <sys/types.h>
13b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov#include <sys/wait.h>
14b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov#include <err.h>
15b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov
16b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanovint main(int argc, char *argv[])
17b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov{
18b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov	struct flock fl;
19b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov	const char *file = /* argv[1]; */
20b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov			   "mmap_fcntl_bug.c";
21b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov	int fd, status;
22b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov
23b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov	if (!file)
24b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov		errx(1, "Usage: %s <normal-file>", argv[0]);
25b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov
26b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov	fd = open(file, O_RDWR);
27b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov	if (fd < 0)
28b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov		err(1, "Opening %s", file);
29b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov
30b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov	fl.l_type = F_WRLCK;
31b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov	fl.l_whence = SEEK_SET;
32b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov	fl.l_start = 0;
33b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov	fl.l_len = 1;
34b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov
35b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov	/* I'm assuming noone else tries to lock this! */
36b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov	if (fcntl(fd, F_SETLK, &fl) != 0)
37b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov		err(1, "Locking %s", file);
38b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov
39b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov	/* If under valgrind, mmap re-opens and closes file, screwing us */
40b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov	if (mmap(NULL, getpagesize(), PROT_READ|PROT_WRITE, MAP_PRIVATE, fd, 0) == MAP_FAILED)
41b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov		err(1, "mmap of %s", file);
42b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov
43b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov	switch (fork()) {
44b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov	case 0:
45b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov		/* Child.  Lock should fail. */
46b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov		if (fcntl(fd, F_SETLK, &fl) == 0)
47b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov			exit(1);
48b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov		exit(0);
49b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov	case -1:
50b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov		err(1, "Fork failed");
51b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov	}
52b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov
53b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov	if (wait(&status) == -1)
54b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov		 err(1, "Child vanished?");
55b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov
56b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov	if (!WIFEXITED(status))
57b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov		errx(1, "Child died with signal %i", WTERMSIG(status));
58b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov
59b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov	switch (WEXITSTATUS(status)) {
60b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov	case 1:
61b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov		errx(1, "Child got lock, we must have dropped it (TEST FAILED)");
62b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov	case 0:
63b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov		fprintf(stderr, "Child exited with zero (TEST PASSED).\n");
64b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov		return 0;
65b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov	default:
66b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov		errx(1, "Child weird exit status %i", WEXITSTATUS(status));
67b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov	}
68b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov}
69