xref: /freebsd/sys/contrib/openzfs/cmd/zed/zed_file.c (revision 61145dc2b94f12f6a47344fb9aac702321880e43)
1 // SPDX-License-Identifier: CDDL-1.0
2 /*
3  * This file is part of the ZFS Event Daemon (ZED).
4  *
5  * Developed at Lawrence Livermore National Laboratory (LLNL-CODE-403049).
6  * Copyright (C) 2013-2014 Lawrence Livermore National Security, LLC.
7  * Refer to the OpenZFS git commit log for authoritative copyright attribution.
8  *
9  * The contents of this file are subject to the terms of the
10  * Common Development and Distribution License Version 1.0 (CDDL-1.0).
11  * You can obtain a copy of the license from the top-level file
12  * "OPENSOLARIS.LICENSE" or at <http://opensource.org/licenses/CDDL-1.0>.
13  * You may not use this file except in compliance with the license.
14  */
15 
16 #include <dirent.h>
17 #include <errno.h>
18 #include <fcntl.h>
19 #include <limits.h>
20 #include <string.h>
21 #include <sys/stat.h>
22 #include <sys/types.h>
23 #include <unistd.h>
24 #include "zed_file.h"
25 #include "zed_log.h"
26 
27 /*
28  * Set an exclusive advisory lock on the open file descriptor [fd].
29  * Return 0 on success, 1 if a conflicting lock is held by another process,
30  * or -1 on error (with errno set).
31  */
32 int
zed_file_lock(int fd)33 zed_file_lock(int fd)
34 {
35 	struct flock lock;
36 
37 	if (fd < 0) {
38 		errno = EBADF;
39 		return (-1);
40 	}
41 	lock.l_type = F_WRLCK;
42 	lock.l_whence = SEEK_SET;
43 	lock.l_start = 0;
44 	lock.l_len = 0;
45 
46 	if (fcntl(fd, F_SETLK, &lock) < 0) {
47 		if ((errno == EACCES) || (errno == EAGAIN))
48 			return (1);
49 
50 		return (-1);
51 	}
52 	return (0);
53 }
54 
55 /*
56  * Release an advisory lock held on the open file descriptor [fd].
57  * Return 0 on success, or -1 on error (with errno set).
58  */
59 int
zed_file_unlock(int fd)60 zed_file_unlock(int fd)
61 {
62 	struct flock lock;
63 
64 	if (fd < 0) {
65 		errno = EBADF;
66 		return (-1);
67 	}
68 	lock.l_type = F_UNLCK;
69 	lock.l_whence = SEEK_SET;
70 	lock.l_start = 0;
71 	lock.l_len = 0;
72 
73 	if (fcntl(fd, F_SETLK, &lock) < 0)
74 		return (-1);
75 
76 	return (0);
77 }
78 
79 /*
80  * Test whether an exclusive advisory lock could be obtained for the open
81  * file descriptor [fd].
82  * Return 0 if the file is not locked, >0 for the PID of another process
83  * holding a conflicting lock, or -1 on error (with errno set).
84  */
85 pid_t
zed_file_is_locked(int fd)86 zed_file_is_locked(int fd)
87 {
88 	struct flock lock;
89 
90 	if (fd < 0) {
91 		errno = EBADF;
92 		return (-1);
93 	}
94 	lock.l_type = F_WRLCK;
95 	lock.l_whence = SEEK_SET;
96 	lock.l_start = 0;
97 	lock.l_len = 0;
98 
99 	if (fcntl(fd, F_GETLK, &lock) < 0)
100 		return (-1);
101 
102 	if (lock.l_type == F_UNLCK)
103 		return (0);
104 
105 	return (lock.l_pid);
106 }
107 
108 
109 #if __APPLE__
110 #define	PROC_SELF_FD "/dev/fd"
111 #else /* Linux-compatible layout */
112 #define	PROC_SELF_FD "/proc/self/fd"
113 #endif
114 
115 /*
116  * Close all open file descriptors greater than or equal to [lowfd].
117  * Any errors encountered while closing file descriptors are ignored.
118  */
119 void
zed_file_close_from(int lowfd)120 zed_file_close_from(int lowfd)
121 {
122 	int errno_bak = errno;
123 	int maxfd = 0;
124 	int fd;
125 	DIR *fddir;
126 	struct dirent *fdent;
127 
128 	if ((fddir = opendir(PROC_SELF_FD)) != NULL) {
129 		while ((fdent = readdir(fddir)) != NULL) {
130 			fd = atoi(fdent->d_name);
131 			if (fd > maxfd && fd != dirfd(fddir))
132 				maxfd = fd;
133 		}
134 		(void) closedir(fddir);
135 	} else {
136 		maxfd = sysconf(_SC_OPEN_MAX);
137 	}
138 	for (fd = lowfd; fd < maxfd; fd++)
139 		(void) close(fd);
140 
141 	errno = errno_bak;
142 }
143