1 /* Test that closing O_PATH descriptors does not release POSIX advisory locks.
2    Copyright (C) 2020-2021 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
subprocess(void * closure)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, 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
probe_lock(void)53 probe_lock (void)
54 {
55   *shared_errno = -1;
56   support_isolate_in_subprocess (subprocess, NULL);
57   if (*shared_errno == 0)
58     /* Lock was aquired 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
do_test(void)70 do_test (void)
71 {
72   shared_errno = support_shared_allocate (sizeof (*shared_errno));
73   int fd = create_temp_file ("tst-o_path-locks-", &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 (path);
96   support_shared_free (shared_errno);
97   return 0;
98 }
99 
100 #include <support/test-driver.c>
101