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 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 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 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 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