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