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