1 // SPDX-License-Identifier: CDDL-1.0
2 /*
3 * CDDL HEADER START
4 *
5 * The contents of this file are subject to the terms of the
6 * Common Development and Distribution License (the "License").
7 * You may not use this file except in compliance with the License.
8 *
9 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
10 * or https://opensource.org/licenses/CDDL-1.0.
11 * See the License for the specific language governing permissions
12 * and limitations under the License.
13 *
14 * When distributing Covered Code, include this CDDL HEADER in each
15 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
16 * If applicable, add the following below this CDDL HEADER, with the
17 * fields enclosed by brackets "[]" replaced with your own identifying
18 * information: Portions Copyright [yyyy] [name of copyright owner]
19 *
20 * CDDL HEADER END
21 */
22
23 /*
24 * Copyright (c) 2026, TrueNAS.
25 */
26
27 /*
28 * This is a sanity check test for the F_SETLEASE and F_GETLEASE fcntl() calls.
29 * We use the generic kernel implementation, but we want to be alerted if it
30 * ever breaks.
31 *
32 * This is not a comprehensive test. It would be nice if it could be!
33 */
34
35 #ifndef _GNU_SOURCE
36 #define _GNU_SOURCE
37 #endif
38
39 #include <stdio.h>
40 #include <unistd.h>
41 #include <stdlib.h>
42 #include <fcntl.h>
43 #include <errno.h>
44 #include <string.h>
45
46 static int
get_lease(int fd)47 get_lease(int fd) {
48 int r = fcntl(fd, F_GETLEASE);
49 if (r < 0) {
50 perror("fcntl(GETLEASE)");
51 exit(2);
52 }
53 return (r);
54 }
55
56 static int
set_lease(int fd,int lease)57 set_lease(int fd, int lease) {
58 return (fcntl(fd, F_SETLEASE, lease) < 0 ? errno : 0);
59 }
60
61 static const char *lease_str[] = {
62 [F_RDLCK] = "RDLCK",
63 [F_WRLCK] = "WRLCK",
64 [F_UNLCK] = "UNLCK",
65 };
66
67 static void
assert_lease(int fd,int expect)68 assert_lease(int fd, int expect) {
69 int got = get_lease(fd);
70 if (got != expect) {
71 fprintf(stderr, "ASSERT_LEASE: expected %s [%d], got %s [%d]\n",
72 lease_str[expect], expect, lease_str[got], got);
73 abort();
74 }
75 printf("ok: lease is %s\n", lease_str[got]);
76 }
77
78 static void
assert_set_lease(int fd,int lease)79 assert_set_lease(int fd, int lease) {
80 int err = set_lease(fd, lease);
81 if (err != 0) {
82 fprintf(stderr, "ASSERT_SET_LEASE: tried %s [%d], error: %s\n",
83 lease_str[lease], lease, strerror(err));
84 abort();
85 }
86 printf("ok: set lease to %s\n", lease_str[lease]);
87 }
88
89 int
main(int argc,char ** argv)90 main(int argc, char **argv)
91 {
92 if (argc != 2) {
93 fprintf(stderr, "usage: %s <filename>\n", argv[0]);
94 exit(1);
95 }
96
97 /* create and open file, read+write */
98 int fd = open(argv[1], O_CREAT|O_RDONLY, S_IRWXU|S_IRWXG|S_IRWXO);
99 if (fd < 0) {
100 perror("open");
101 exit(2);
102 }
103 printf("ok: opened file RDONLY\n");
104
105 /* fd starts with no lease */
106 assert_lease(fd, F_UNLCK);
107
108 /* fd is readonly, so can take read lease */
109 assert_set_lease(fd, F_RDLCK);
110 /* confirm read lease */
111 assert_lease(fd, F_RDLCK);
112
113 /* no other openers, so can take write lease */
114 assert_set_lease(fd, F_WRLCK);
115 /* confirm write lease */
116 assert_lease(fd, F_WRLCK);
117
118 /* release lease */
119 assert_set_lease(fd, F_UNLCK);
120 /* confirm lease released */
121 assert_lease(fd, F_UNLCK);
122
123 close(fd);
124
125 return (0);
126 }
127