+ struct thread_info *ti = arg;
+ struct flock *lock = ti->lock;
+ int fd = ti->fd;
+
+ sleep(2);
+ printf("thread 2: unlock: rc = %d\n", ti->rc);
+ lock->l_type = F_UNLCK;
+ ti->rc += t_fcntl(fd, F_SETLK, lock);
+ printf("thread 2: unlock done: rc = %d\n", ti->rc);
+ printf("thread 2: set write lock (non-blocking): rc = %d\n", ti->rc);
+ lock->l_type = F_WRLCK;
+ ti->rc += t_fcntl(fd, F_SETLK, lock);
+ printf("thread 2: set write lock done: rc = %d\n", ti->rc);
+ (void)t_fcntl(fd, F_GETLK, lock); /* ignore this, operation will fail */
+
+ if (ti->rc)
+ fprintf(stdout, "thread2 exiting with rc = %d\n", ti->rc);
+ return &ti->rc;
+}
+
+int t2(int argc, char *argv[])
+{
+ struct flock lock = {
+ .l_type = F_RDLCK,
+ .l_whence = SEEK_SET,
+ };
+ char file[MAX_PATH_LENGTH] = "";
+ int fd, rc;
+ pthread_t th1, th2;
+ struct thread_info ti;
+
+ snprintf(file, MAX_PATH_LENGTH, "%s/test_t2_file", argv[2]);
+
+ fd = open(file, O_RDWR|O_CREAT, (mode_t)0666);
+ if (fd < 0) {
+ fprintf(stderr, "error open file '%s': %s\n", file,
+ strerror(errno));
+ return EXIT_FAILURE;
+ }
+
+ t_fcntl(fd, F_SETFL, O_APPEND);
+ rc = t_fcntl(fd, F_GETFL);
+ if ((rc < 0) || (rc & O_APPEND) == 0) {
+ fprintf(stderr, "error get flag: ret %x\n", rc);
+ rc = EXIT_FAILURE;
+ goto out;
+ }
+
+ ti.lock = &lock;
+ ti.fd = fd;
+ ti.rc = 0;
+ rc = pthread_create(&th1, NULL, t2_thread1, &ti);
+ if (rc) {
+ fprintf(stderr, "error create thread 1\n");
+ rc = EXIT_FAILURE;
+ goto out;
+ }
+ rc = pthread_create(&th2, NULL, t2_thread2, &ti);
+ if (rc) {
+ fprintf(stderr, "error create thread 2\n");
+ rc = EXIT_FAILURE;
+ goto out;
+ }
+ pthread_join(th1, NULL);
+ pthread_join(th2, NULL);
+ if (ti.rc)
+ rc = EXIT_FAILURE;
+out:
+ t_unlink(file);
+ close(fd);
+
+ return rc;
+}
+
+/** =================================================================
+ * test number 3
+ *
+ * Bug 24040: Two conflicting flocks from same process different fds should fail
+ * two conflicting flocks from different processes but same fs
+ * should succeed.
+ */
+int t3(int argc, char *argv[])
+{
+ int fd, fd2;
+ int pid;
+ int rc = EXIT_SUCCESS;
+
+ if (argc != 3) {
+ fprintf(stderr, "usage: flocks_test 3 filename\n");
+ return EXIT_FAILURE;
+ }
+
+ fd = open(argv[2], O_RDWR);
+ if (fd < 0) {
+ fprintf(stderr, "Couldn't open file '%s': %s\n", argv[2],
+ strerror(errno));
+ return EXIT_FAILURE;
+ }
+ if (flock(fd, LOCK_EX | LOCK_NB) < 0) {
+ perror("first flock failed");
+ rc = EXIT_FAILURE;
+ goto out;
+ }
+ fd2 = open(argv[2], O_RDWR);
+ if (fd2 < 0) {
+ fprintf(stderr, "Couldn't open file '%s': %s\n", argv[2],
+ strerror(errno));
+ rc = EXIT_FAILURE;
+ goto out;
+ }
+ if (flock(fd2, LOCK_EX | LOCK_NB) >= 0) {
+ fprintf(stderr, "Second flock succeeded - FAIL\n");
+ rc = EXIT_FAILURE;
+ close(fd2);
+ goto out;
+ }
+
+ close(fd2);
+
+ pid = fork();
+ if (pid == -1) {
+ perror("fork");
+ rc = EXIT_FAILURE;
+ goto out;
+ }
+
+ if (pid == 0) {
+ fd2 = open(argv[2], O_RDWR);
+ if (fd2 < 0) {
+ fprintf(stderr, "Couldn't open file '%s': %s\n",
+ argv[1], strerror(errno));
+ rc = EXIT_FAILURE;
+ goto out;
+ }
+ if (flock(fd2, LOCK_EX | LOCK_NB) >= 0) {
+ fprintf(stderr, "Second flock succeeded - FAIL\n");
+ rc = EXIT_FAILURE;
+ goto out_child;
+ }
+ if (flock(fd, LOCK_UN) == -1) {
+ fprintf(stderr, "Child unlock on parent fd failed\n");
+ rc = EXIT_FAILURE;
+ goto out_child;
+ }
+ if (flock(fd2, LOCK_EX | LOCK_NB) == -1) {
+ fprintf(stderr, "Relock after parent unlock failed!\n");
+ rc = EXIT_FAILURE;
+ goto out_child;
+ }
+ out_child:
+ close(fd2);
+ exit(rc);
+ }
+
+ waitpid(pid, &rc, 0);
+out:
+ close(fd);
+ return rc;