1 | /* Test that closing O_PATH descriptors does not release POSIX advisory locks. |
2 | Copyright (C) 2020-2024 Free Software Foundation, Inc. |
3 | This file is part of the GNU C Library. |
4 | |
5 | The GNU C Library is free software; you can redistribute it and/or |
6 | modify it under the terms of the GNU Lesser General Public |
7 | License as published by the Free Software Foundation; either |
8 | version 2.1 of the License, or (at your option) any later version. |
9 | |
10 | The GNU C Library is distributed in the hope that it will be useful, |
11 | but WITHOUT ANY WARRANTY; without even the implied warranty of |
12 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
13 | Lesser General Public License for more details. |
14 | |
15 | You should have received a copy of the GNU Lesser General Public |
16 | License along with the GNU C Library; if not, see |
17 | <https://www.gnu.org/licenses/>. */ |
18 | |
19 | #include <errno.h> |
20 | #include <fcntl.h> |
21 | #include <stdbool.h> |
22 | #include <stdlib.h> |
23 | #include <support/check.h> |
24 | #include <support/namespace.h> |
25 | #include <support/support.h> |
26 | #include <support/temp_file.h> |
27 | #include <support/xunistd.h> |
28 | |
29 | /* The subprocess writes the errno value of the lock operation |
30 | here. */ |
31 | static int *shared_errno; |
32 | |
33 | /* The path of the temporary file which is locked. */ |
34 | static char *path; |
35 | |
36 | /* Try to obtain an exclusive lock on the file at path. */ |
37 | static void |
38 | subprocess (void *closure) |
39 | { |
40 | int fd = xopen (path, O_RDWR, 0); |
41 | struct flock64 lock = { .l_type = F_WRLCK, }; |
42 | int ret = fcntl64 (fd: fd, F_SETLK, &lock); |
43 | if (ret == 0) |
44 | *shared_errno = 0; |
45 | else |
46 | *shared_errno = errno; |
47 | xclose (fd); |
48 | } |
49 | |
50 | /* Return true if the file at path is currently locked, false if |
51 | not. */ |
52 | static bool |
53 | probe_lock (void) |
54 | { |
55 | *shared_errno = -1; |
56 | support_isolate_in_subprocess (callback: subprocess, NULL); |
57 | if (*shared_errno == 0) |
58 | /* Lock was acquired by the subprocess, so this process has not |
59 | locked it. */ |
60 | return false; |
61 | else |
62 | { |
63 | /* POSIX allows both EACCES and EAGAIN. Linux use EACCES. */ |
64 | TEST_COMPARE (*shared_errno, EAGAIN); |
65 | return true; |
66 | } |
67 | } |
68 | |
69 | static int |
70 | do_test (void) |
71 | { |
72 | shared_errno = support_shared_allocate (size: sizeof (*shared_errno)); |
73 | int fd = create_temp_file (base: "tst-o_path-locks-" , filename: &path); |
74 | |
75 | /* The file is not locked initially. */ |
76 | TEST_VERIFY (!probe_lock ()); |
77 | |
78 | struct flock64 lock = { .l_type = F_WRLCK, }; |
79 | TEST_COMPARE (fcntl64 (fd, F_SETLK, &lock), 0); |
80 | |
81 | /* The lock has been acquired. */ |
82 | TEST_VERIFY (probe_lock ()); |
83 | |
84 | /* Closing the same file via a different descriptor releases the |
85 | lock. */ |
86 | xclose (xopen (path, O_RDONLY, 0)); |
87 | TEST_VERIFY (!probe_lock ()); |
88 | |
89 | /* But not if it is an O_PATH descriptor. */ |
90 | TEST_COMPARE (fcntl64 (fd, F_SETLK, &lock), 0); |
91 | xclose (xopen (path, O_PATH, 0)); |
92 | TEST_VERIFY (probe_lock ()); |
93 | |
94 | xclose (fd); |
95 | free (ptr: path); |
96 | support_shared_free (shared_errno); |
97 | return 0; |
98 | } |
99 | |
100 | #include <support/test-driver.c> |
101 | |