1 /* Test of flock() function. 2 Copyright (C) 2008-2021 Free Software Foundation, Inc. 3 4 This program is free software: you can redistribute it and/or modify 5 it under the terms of the GNU General Public License as published by 6 the Free Software Foundation; either version 3 of the License, or 7 (at your option) any later version. 8 9 This program is distributed in the hope that it will be useful, 10 but WITHOUT ANY WARRANTY; without even the implied warranty of 11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 GNU General Public License for more details. 13 14 You should have received a copy of the GNU General Public License 15 along with this program. If not, see <https://www.gnu.org/licenses/>. */ 16 17 #include <config.h> 18 19 #include <sys/file.h> 20 21 #include "signature.h" 22 SIGNATURE_CHECK (flock, int, (int, int)); 23 24 #include <fcntl.h> 25 #include <unistd.h> 26 #include <errno.h> 27 28 #include "macros.h" 29 30 static void 31 test_shared (const char *file, int fd) /* */ 32 { 33 /* Should be able to acquire several shared locks on a file, through 34 * different file table entries. 35 */ 36 int fd2, r; 37 38 ASSERT (flock (fd, LOCK_SH) == 0); 39 40 fd2 = open (file, O_RDWR, 0644); 41 ASSERT (fd2 >= 0); 42 43 r = flock (fd2, LOCK_SH | LOCK_NB); 44 ASSERT (r == 0); /* Was able to acquire a second shared lock. */ 45 46 ASSERT (flock (fd, LOCK_UN) == 0); 47 ASSERT (close (fd2) == 0); 48 } 49 50 static void 51 test_exclusive (const char *file, int fd) /* */ 52 { 53 /* Should not be able to acquire more than one exclusive lock on a file. */ 54 int fd2, r; 55 56 ASSERT (flock (fd, LOCK_EX) == 0); 57 58 fd2 = open (file, O_RDWR, 0644); 59 ASSERT (fd2 >= 0); 60 61 r = flock (fd2, LOCK_EX | LOCK_NB); 62 ASSERT (r == -1); /* Was unable to acquire a second exclusive lock. */ 63 64 #if 0 65 /* The Linux manual page of flock(2) says: 66 "A process may only hold one type of lock (shared or exclusive) on a 67 file. Subsequent flock() calls on an already locked file will convert 68 an existing lock to the new lock mode." 69 So, the call below should convert the exclusive lock for fd to a shared 70 and thus succeeds. The fact that it doesn't but instead fails is 71 apparently a bug. */ 72 /* The Solaris manual page of flock(2) says: 73 "More than one process may hold a shared lock for a file at any given 74 time, but multiple exclusive, or both shared and exclusive, locks may 75 not exist simultaneously on a file. ... 76 Requesting a lock on an object that is already locked normally causes 77 the caller to block until the lock may be acquired. If LOCK_NB is 78 included in operation, then this will not happen; instead, the call 79 will fail and the error EWOULDBLOCK will be returned." 80 So, the call below should fail and set errno to EWOULDBLOCK. The fact 81 that it succeeds is apparently a bug. */ 82 r = flock (fd2, LOCK_SH | LOCK_NB); 83 ASSERT (r == -1); 84 #endif 85 86 ASSERT (flock (fd, LOCK_UN) == 0); 87 ASSERT (close (fd2) == 0); 88 } 89 90 int 91 main (int argc, char *argv[]) /* */ 92 { 93 int fd; 94 const char *file = "test-flock.txt"; 95 96 /* Open a non-empty file for testing. */ 97 fd = open (file, O_RDWR | O_CREAT | O_TRUNC, 0644); 98 ASSERT (fd >= 0); 99 ASSERT (write (fd, "hello", 5) == 5); 100 101 #if defined __linux__ || defined __ANDROID__ 102 /* Invalid operation codes are rejected by the Linux implementation and by 103 the gnulib replacement, but not by the Mac OS X implementation. */ 104 ASSERT (flock (fd, LOCK_SH | LOCK_EX) == -1); 105 ASSERT (errno == EINVAL); 106 ASSERT (flock (fd, LOCK_SH | LOCK_UN) == -1); 107 ASSERT (errno == EINVAL); 108 ASSERT (flock (fd, LOCK_EX | LOCK_UN) == -1); 109 ASSERT (errno == EINVAL); 110 ASSERT (flock (fd, 0) == -1); 111 ASSERT (errno == EINVAL); 112 #endif 113 114 test_shared (file, fd); 115 test_exclusive (file, fd); 116 117 /* Close and remove the test file. */ 118 ASSERT (close (fd) == 0); 119 ASSERT (unlink (file) == 0); 120 121 return 0; 122 }