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
zed_file_lock(int fd)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
zed_file_unlock(int fd)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
zed_file_is_locked(int fd)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
zed_file_close_from(int lowfd)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