1 | /* Test POSIX lock on an open file (lockf). |
2 | Copyright (C) 2019-2022 Free Software Foundation, Inc. |
3 | |
4 | This program is free software; you can redistribute it and/or |
5 | modify it under the terms of the GNU General Public License |
6 | as published by the Free Software Foundation; either version 2 |
7 | of the License, or (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 | |
18 | #include <unistd.h> |
19 | #include <stdint.h> |
20 | #include <errno.h> |
21 | #include <stdio.h> |
22 | |
23 | #include <support/temp_file.h> |
24 | #include <support/capture_subprocess.h> |
25 | #include <support/check.h> |
26 | |
27 | #ifndef TST_LOCKFD |
28 | # define TST_LOCKFD "tst-lockfd." |
29 | #endif |
30 | #ifndef LOCKF |
31 | # define LOCKF lockf |
32 | #endif |
33 | #ifndef LOCKF64 |
34 | # define LOCKF64 lockf64 |
35 | #endif |
36 | |
37 | static char *temp_filename; |
38 | static int temp_fd; |
39 | |
40 | static void |
41 | do_prepare (int argc, char **argv) |
42 | { |
43 | temp_fd = create_temp_file (TST_LOCKFD, filename: &temp_filename); |
44 | TEST_VERIFY_EXIT (temp_fd != -1); |
45 | } |
46 | #define PREPARE do_prepare |
47 | |
48 | static void |
49 | do_test_child_lockf (void *closure) |
50 | { |
51 | /* Check if parent has [0, 1024) locked. */ |
52 | TEST_COMPARE (lseek (temp_fd, 0, SEEK_SET), 0); |
53 | TEST_COMPARE (LOCKF (temp_fd, F_TLOCK, 1024), -1); |
54 | TEST_COMPARE (errno, EAGAIN); |
55 | TEST_COMPARE (LOCKF (temp_fd, F_TEST, 1024), -1); |
56 | TEST_COMPARE (errno, EACCES); |
57 | /* Also Check if parent has last 1024 bytes locked. */ |
58 | TEST_COMPARE (lseek (temp_fd, INT32_MAX-1024, SEEK_SET), INT32_MAX-1024); |
59 | TEST_COMPARE (LOCKF (temp_fd, F_TEST, 1024), -1); |
60 | |
61 | /* And try to lock [1024, 2048). */ |
62 | TEST_COMPARE (lseek (temp_fd, 1024, SEEK_SET), 1024); |
63 | TEST_COMPARE (LOCKF (temp_fd, F_LOCK, 1024), 0); |
64 | |
65 | /* Check if non-LFS interface cap access to 32-bif off_t. */ |
66 | TEST_COMPARE (lseek64 (temp_fd, (off64_t)INT32_MAX, SEEK_SET), |
67 | (off64_t)INT32_MAX); |
68 | TEST_COMPARE (LOCKF64 (temp_fd, F_TEST, 1024), 0); |
69 | } |
70 | |
71 | static void |
72 | do_test_child_lockf64 (void *closure) |
73 | { |
74 | /* Check if parent has [0, 1024) locked. */ |
75 | TEST_COMPARE (lseek64 (temp_fd, 0, SEEK_SET), 0); |
76 | TEST_COMPARE (LOCKF64 (temp_fd, F_TLOCK, 1024), -1); |
77 | TEST_COMPARE (errno, EAGAIN); |
78 | TEST_COMPARE (LOCKF64 (temp_fd, F_TEST, 1024), -1); |
79 | TEST_COMPARE (errno, EACCES); |
80 | /* Also Check if parent has last 1024 bytes locked. */ |
81 | TEST_COMPARE (lseek64 (temp_fd, INT32_MAX-1024, SEEK_SET), INT32_MAX-1024); |
82 | TEST_COMPARE (LOCKF64 (temp_fd, F_TEST, 1024), -1); |
83 | |
84 | /* And try to lock [1024, 2048). */ |
85 | TEST_COMPARE (lseek64 (temp_fd, 1024, SEEK_SET), 1024); |
86 | TEST_COMPARE (LOCKF64 (temp_fd, F_LOCK, 1024), 0); |
87 | |
88 | /* And also [INT32_MAX, INT32_MAX+1024). */ |
89 | { |
90 | off64_t off = (off64_t)INT32_MAX; |
91 | TEST_COMPARE (lseek64 (temp_fd, off, SEEK_SET), off); |
92 | TEST_COMPARE (LOCKF64 (temp_fd, F_LOCK, 1024), 0); |
93 | } |
94 | |
95 | /* Check if [INT32_MAX+1024, INT64_MAX) is locked. */ |
96 | { |
97 | off64_t off = (off64_t)INT32_MAX+1024; |
98 | TEST_COMPARE (lseek64 (temp_fd, off, SEEK_SET), off); |
99 | TEST_COMPARE (LOCKF64 (temp_fd, F_TLOCK, 1024), -1); |
100 | TEST_COMPARE (errno, EAGAIN); |
101 | TEST_COMPARE (LOCKF64 (temp_fd, F_TEST, 1024), -1); |
102 | TEST_COMPARE (errno, EACCES); |
103 | } |
104 | } |
105 | |
106 | static int |
107 | do_test (void) |
108 | { |
109 | /* Basic tests to check if a lock can be obtained and checked. */ |
110 | TEST_COMPARE (LOCKF (temp_fd, F_LOCK, 1024), 0); |
111 | TEST_COMPARE (LOCKF (temp_fd, F_LOCK, INT32_MAX), 0); |
112 | TEST_COMPARE (LOCKF (temp_fd, F_TLOCK, 1024), 0); |
113 | TEST_COMPARE (LOCKF (temp_fd, F_TEST, 1024), 0); |
114 | TEST_COMPARE (lseek (temp_fd, 1024, SEEK_SET), 1024); |
115 | TEST_COMPARE (LOCKF (temp_fd, F_ULOCK, 1024), 0); |
116 | /* Parent process should have ([0, 1024), [2048, INT32_MAX)) ranges locked. */ |
117 | |
118 | { |
119 | struct support_capture_subprocess result; |
120 | result = support_capture_subprocess (callback: do_test_child_lockf, NULL); |
121 | support_capture_subprocess_check (&result, context: "LOCKF" , status_or_signal: 0, allowed: sc_allow_none); |
122 | } |
123 | |
124 | if (sizeof (off_t) != sizeof (off64_t)) |
125 | { |
126 | /* Check if previously locked regions with LFS symbol. */ |
127 | TEST_COMPARE (lseek (temp_fd, 0, SEEK_SET), 0); |
128 | TEST_COMPARE (LOCKF64 (temp_fd, F_LOCK, 1024), 0); |
129 | TEST_COMPARE (LOCKF64 (temp_fd, F_TLOCK, 1024), 0); |
130 | TEST_COMPARE (LOCKF64 (temp_fd, F_TEST, 1024), 0); |
131 | /* Lock region [INT32_MAX+1024, INT64_MAX). */ |
132 | off64_t off = (off64_t)INT32_MAX + 1024; |
133 | TEST_COMPARE (lseek64 (temp_fd, off, SEEK_SET), off); |
134 | TEST_COMPARE (LOCKF64 (temp_fd, F_LOCK, 1024), 0); |
135 | /* Parent process should have ([0, 1024), [2048, INT32_MAX), |
136 | [INT32_MAX+1024, INT64_MAX)) ranges locked. */ |
137 | |
138 | { |
139 | struct support_capture_subprocess result; |
140 | result = support_capture_subprocess (callback: do_test_child_lockf64, NULL); |
141 | support_capture_subprocess_check (&result, context: "LOCKF" , status_or_signal: 0, allowed: sc_allow_none); |
142 | } |
143 | } |
144 | |
145 | return 0; |
146 | } |
147 | |
148 | #include <support/test-driver.c> |
149 | |