| /* |
| * This file is part of the ZFS Event Daemon (ZED). |
| * |
| * Developed at Lawrence Livermore National Laboratory (LLNL-CODE-403049). |
| * Copyright (C) 2013-2014 Lawrence Livermore National Security, LLC. |
| * Refer to the OpenZFS git commit log for authoritative copyright attribution. |
| * |
| * The contents of this file are subject to the terms of the |
| * Common Development and Distribution License Version 1.0 (CDDL-1.0). |
| * You can obtain a copy of the license from the top-level file |
| * "OPENSOLARIS.LICENSE" or at <http://opensource.org/licenses/CDDL-1.0>. |
| * You may not use this file except in compliance with the license. |
| */ |
| |
| #include <dirent.h> |
| #include <errno.h> |
| #include <fcntl.h> |
| #include <limits.h> |
| #include <string.h> |
| #include <sys/stat.h> |
| #include <sys/types.h> |
| #include <unistd.h> |
| #include "zed_file.h" |
| #include "zed_log.h" |
| |
| /* |
| * Set an exclusive advisory lock on the open file descriptor [fd]. |
| * Return 0 on success, 1 if a conflicting lock is held by another process, |
| * or -1 on error (with errno set). |
| */ |
| int |
| zed_file_lock(int fd) |
| { |
| struct flock lock; |
| |
| if (fd < 0) { |
| errno = EBADF; |
| return (-1); |
| } |
| lock.l_type = F_WRLCK; |
| lock.l_whence = SEEK_SET; |
| lock.l_start = 0; |
| lock.l_len = 0; |
| |
| if (fcntl(fd, F_SETLK, &lock) < 0) { |
| if ((errno == EACCES) || (errno == EAGAIN)) |
| return (1); |
| |
| return (-1); |
| } |
| return (0); |
| } |
| |
| /* |
| * Release an advisory lock held on the open file descriptor [fd]. |
| * Return 0 on success, or -1 on error (with errno set). |
| */ |
| int |
| zed_file_unlock(int fd) |
| { |
| struct flock lock; |
| |
| if (fd < 0) { |
| errno = EBADF; |
| return (-1); |
| } |
| lock.l_type = F_UNLCK; |
| lock.l_whence = SEEK_SET; |
| lock.l_start = 0; |
| lock.l_len = 0; |
| |
| if (fcntl(fd, F_SETLK, &lock) < 0) |
| return (-1); |
| |
| return (0); |
| } |
| |
| /* |
| * Test whether an exclusive advisory lock could be obtained for the open |
| * file descriptor [fd]. |
| * Return 0 if the file is not locked, >0 for the PID of another process |
| * holding a conflicting lock, or -1 on error (with errno set). |
| */ |
| pid_t |
| zed_file_is_locked(int fd) |
| { |
| struct flock lock; |
| |
| if (fd < 0) { |
| errno = EBADF; |
| return (-1); |
| } |
| lock.l_type = F_WRLCK; |
| lock.l_whence = SEEK_SET; |
| lock.l_start = 0; |
| lock.l_len = 0; |
| |
| if (fcntl(fd, F_GETLK, &lock) < 0) |
| return (-1); |
| |
| if (lock.l_type == F_UNLCK) |
| return (0); |
| |
| return (lock.l_pid); |
| } |
| |
| |
| #if __APPLE__ |
| #define PROC_SELF_FD "/dev/fd" |
| #else /* Linux-compatible layout */ |
| #define PROC_SELF_FD "/proc/self/fd" |
| #endif |
| |
| /* |
| * Close all open file descriptors greater than or equal to [lowfd]. |
| * Any errors encountered while closing file descriptors are ignored. |
| */ |
| void |
| zed_file_close_from(int lowfd) |
| { |
| int errno_bak = errno; |
| int maxfd = 0; |
| int fd; |
| DIR *fddir; |
| struct dirent *fdent; |
| |
| if ((fddir = opendir(PROC_SELF_FD)) != NULL) { |
| while ((fdent = readdir(fddir)) != NULL) { |
| fd = atoi(fdent->d_name); |
| if (fd > maxfd && fd != dirfd(fddir)) |
| maxfd = fd; |
| } |
| (void) closedir(fddir); |
| } else { |
| maxfd = sysconf(_SC_OPEN_MAX); |
| } |
| for (fd = lowfd; fd < maxfd; fd++) |
| (void) close(fd); |
| |
| errno = errno_bak; |
| } |