xref: /freebsd/sys/contrib/openzfs/cmd/zed/zed_file.c (revision c66ec88fed842fbaad62c30d510644ceb7bd2d71)
1 /*
2  * This file is part of the ZFS Event Daemon (ZED).
3  *
4  * Developed at Lawrence Livermore National Laboratory (LLNL-CODE-403049).
5  * Copyright (C) 2013-2014 Lawrence Livermore National Security, LLC.
6  * Refer to the ZoL git commit log for authoritative copyright attribution.
7  *
8  * The contents of this file are subject to the terms of the
9  * Common Development and Distribution License Version 1.0 (CDDL-1.0).
10  * You can obtain a copy of the license from the top-level file
11  * "OPENSOLARIS.LICENSE" or at <http://opensource.org/licenses/CDDL-1.0>.
12  * You may not use this file except in compliance with the license.
13  */
14 
15 #include <errno.h>
16 #include <fcntl.h>
17 #include <limits.h>
18 #include <string.h>
19 #include <sys/resource.h>
20 #include <sys/stat.h>
21 #include <sys/types.h>
22 #include <unistd.h>
23 #include "zed_file.h"
24 #include "zed_log.h"
25 
26 /*
27  * Read up to [n] bytes from [fd] into [buf].
28  * Return the number of bytes read, 0 on EOF, or -1 on error.
29  */
30 ssize_t
31 zed_file_read_n(int fd, void *buf, size_t n)
32 {
33 	unsigned char *p;
34 	size_t n_left;
35 	ssize_t n_read;
36 
37 	p = buf;
38 	n_left = n;
39 	while (n_left > 0) {
40 		if ((n_read = read(fd, p, n_left)) < 0) {
41 			if (errno == EINTR)
42 				continue;
43 			else
44 				return (-1);
45 
46 		} else if (n_read == 0) {
47 			break;
48 		}
49 		n_left -= n_read;
50 		p += n_read;
51 	}
52 	return (n - n_left);
53 }
54 
55 /*
56  * Write [n] bytes from [buf] out to [fd].
57  * Return the number of bytes written, or -1 on error.
58  */
59 ssize_t
60 zed_file_write_n(int fd, void *buf, size_t n)
61 {
62 	const unsigned char *p;
63 	size_t n_left;
64 	ssize_t n_written;
65 
66 	p = buf;
67 	n_left = n;
68 	while (n_left > 0) {
69 		if ((n_written = write(fd, p, n_left)) < 0) {
70 			if (errno == EINTR)
71 				continue;
72 			else
73 				return (-1);
74 
75 		}
76 		n_left -= n_written;
77 		p += n_written;
78 	}
79 	return (n);
80 }
81 
82 /*
83  * Set an exclusive advisory lock on the open file descriptor [fd].
84  * Return 0 on success, 1 if a conflicting lock is held by another process,
85  * or -1 on error (with errno set).
86  */
87 int
88 zed_file_lock(int fd)
89 {
90 	struct flock lock;
91 
92 	if (fd < 0) {
93 		errno = EBADF;
94 		return (-1);
95 	}
96 	lock.l_type = F_WRLCK;
97 	lock.l_whence = SEEK_SET;
98 	lock.l_start = 0;
99 	lock.l_len = 0;
100 
101 	if (fcntl(fd, F_SETLK, &lock) < 0) {
102 		if ((errno == EACCES) || (errno == EAGAIN))
103 			return (1);
104 
105 		return (-1);
106 	}
107 	return (0);
108 }
109 
110 /*
111  * Release an advisory lock held on the open file descriptor [fd].
112  * Return 0 on success, or -1 on error (with errno set).
113  */
114 int
115 zed_file_unlock(int fd)
116 {
117 	struct flock lock;
118 
119 	if (fd < 0) {
120 		errno = EBADF;
121 		return (-1);
122 	}
123 	lock.l_type = F_UNLCK;
124 	lock.l_whence = SEEK_SET;
125 	lock.l_start = 0;
126 	lock.l_len = 0;
127 
128 	if (fcntl(fd, F_SETLK, &lock) < 0)
129 		return (-1);
130 
131 	return (0);
132 }
133 
134 /*
135  * Test whether an exclusive advisory lock could be obtained for the open
136  * file descriptor [fd].
137  * Return 0 if the file is not locked, >0 for the PID of another process
138  * holding a conflicting lock, or -1 on error (with errno set).
139  */
140 pid_t
141 zed_file_is_locked(int fd)
142 {
143 	struct flock lock;
144 
145 	if (fd < 0) {
146 		errno = EBADF;
147 		return (-1);
148 	}
149 	lock.l_type = F_WRLCK;
150 	lock.l_whence = SEEK_SET;
151 	lock.l_start = 0;
152 	lock.l_len = 0;
153 
154 	if (fcntl(fd, F_GETLK, &lock) < 0)
155 		return (-1);
156 
157 	if (lock.l_type == F_UNLCK)
158 		return (0);
159 
160 	return (lock.l_pid);
161 }
162 
163 /*
164  * Close all open file descriptors greater than or equal to [lowfd].
165  * Any errors encountered while closing file descriptors are ignored.
166  */
167 void
168 zed_file_close_from(int lowfd)
169 {
170 	const int maxfd_def = 256;
171 	int errno_bak;
172 	struct rlimit rl;
173 	int maxfd;
174 	int fd;
175 
176 	errno_bak = errno;
177 
178 	if (getrlimit(RLIMIT_NOFILE, &rl) < 0) {
179 		maxfd = maxfd_def;
180 	} else if (rl.rlim_max == RLIM_INFINITY) {
181 		maxfd = maxfd_def;
182 	} else {
183 		maxfd = rl.rlim_max;
184 	}
185 	for (fd = lowfd; fd < maxfd; fd++)
186 		(void) close(fd);
187 
188 	errno = errno_bak;
189 }
190 
191 /*
192  * Set the CLOEXEC flag on file descriptor [fd] so it will be automatically
193  * closed upon successful execution of one of the exec functions.
194  * Return 0 on success, or -1 on error.
195  *
196  * FIXME: No longer needed?
197  */
198 int
199 zed_file_close_on_exec(int fd)
200 {
201 	int flags;
202 
203 	if (fd < 0) {
204 		errno = EBADF;
205 		return (-1);
206 	}
207 	flags = fcntl(fd, F_GETFD);
208 	if (flags == -1)
209 		return (-1);
210 
211 	flags |= FD_CLOEXEC;
212 
213 	if (fcntl(fd, F_SETFD, flags) == -1)
214 		return (-1);
215 
216 	return (0);
217 }
218