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