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