| /** 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 <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.%d", |
| 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; |
| } |