| /* |
| * This file is part of the ZFS Event Daemon (ZED) |
| * for ZFS on Linux (ZoL) <http://zfsonlinux.org/>. |
| * Developed at Lawrence Livermore National Laboratory (LLNL-CODE-403049). |
| * Copyright (C) 2013-2014 Lawrence Livermore National Security, LLC. |
| * Refer to the ZoL 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 <errno.h> |
| #include <fcntl.h> |
| #include <limits.h> |
| #include <string.h> |
| #include <sys/resource.h> |
| #include <sys/stat.h> |
| #include <sys/types.h> |
| #include <unistd.h> |
| #include "zed_log.h" |
| |
| /* |
| * Read up to [n] bytes from [fd] into [buf]. |
| * Return the number of bytes read, 0 on EOF, or -1 on error. |
| */ |
| ssize_t |
| zed_file_read_n(int fd, void *buf, size_t n) |
| { |
| unsigned char *p; |
| size_t n_left; |
| ssize_t n_read; |
| |
| p = buf; |
| n_left = n; |
| while (n_left > 0) { |
| if ((n_read = read(fd, p, n_left)) < 0) { |
| if (errno == EINTR) |
| continue; |
| else |
| return (-1); |
| |
| } else if (n_read == 0) { |
| break; |
| } |
| n_left -= n_read; |
| p += n_read; |
| } |
| return (n - n_left); |
| } |
| |
| /* |
| * Write [n] bytes from [buf] out to [fd]. |
| * Return the number of bytes written, or -1 on error. |
| */ |
| ssize_t |
| zed_file_write_n(int fd, void *buf, size_t n) |
| { |
| const unsigned char *p; |
| size_t n_left; |
| ssize_t n_written; |
| |
| p = buf; |
| n_left = n; |
| while (n_left > 0) { |
| if ((n_written = write(fd, p, n_left)) < 0) { |
| if (errno == EINTR) |
| continue; |
| else |
| return (-1); |
| |
| } |
| n_left -= n_written; |
| p += n_written; |
| } |
| return (n); |
| } |
| |
| /* |
| * 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); |
| } |
| |
| /* |
| * 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) |
| { |
| const int maxfd_def = 256; |
| int errno_bak; |
| struct rlimit rl; |
| int maxfd; |
| int fd; |
| |
| errno_bak = errno; |
| |
| if (getrlimit(RLIMIT_NOFILE, &rl) < 0) { |
| maxfd = maxfd_def; |
| } else if (rl.rlim_max == RLIM_INFINITY) { |
| maxfd = maxfd_def; |
| } else { |
| maxfd = rl.rlim_max; |
| } |
| for (fd = lowfd; fd < maxfd; fd++) |
| (void) close(fd); |
| |
| errno = errno_bak; |
| } |
| |
| /* |
| * Set the CLOEXEC flag on file descriptor [fd] so it will be automatically |
| * closed upon successful execution of one of the exec functions. |
| * Return 0 on success, or -1 on error. |
| * |
| * FIXME: No longer needed? |
| */ |
| int |
| zed_file_close_on_exec(int fd) |
| { |
| int flags; |
| |
| if (fd < 0) { |
| errno = EBADF; |
| return (-1); |
| } |
| flags = fcntl(fd, F_GETFD); |
| if (flags == -1) |
| return (-1); |
| |
| flags |= FD_CLOEXEC; |
| |
| if (fcntl(fd, F_SETFD, flags) == -1) |
| return (-1); |
| |
| return (0); |
| } |