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