]> granicus.if.org Git - zfs/blob - cmd/zed/zed_file.c
Initial implementation of zed (ZFS Event Daemon)
[zfs] / cmd / zed / zed_file.c
1 /*
2  * CDDL HEADER START
3  *
4  * The contents of this file are subject to the terms of the
5  * Common Development and Distribution License (the "License").
6  * You may not use this file except in compliance with the License.
7  *
8  * You can obtain a copy of the license from the top-level
9  * OPENSOLARIS.LICENSE or <http://opensource.org/licenses/CDDL-1.0>.
10  * See the License for the specific language governing permissions
11  * and limitations under the License.
12  *
13  * When distributing Covered Code, include this CDDL HEADER in each file
14  * and include the License file from the top-level OPENSOLARIS.LICENSE.
15  * If applicable, add the following below this CDDL HEADER, with the
16  * fields enclosed by brackets "[]" replaced with your own identifying
17  * information: Portions Copyright [yyyy] [name of copyright owner]
18  *
19  * CDDL HEADER END
20  */
21
22 /*
23  * Developed at Lawrence Livermore National Laboratory (LLNL-CODE-403049).
24  * Copyright (C) 2013-2014 Lawrence Livermore National Security, LLC.
25  */
26
27 #include <errno.h>
28 #include <fcntl.h>
29 #include <limits.h>
30 #include <string.h>
31 #include <sys/resource.h>
32 #include <sys/stat.h>
33 #include <sys/types.h>
34 #include <unistd.h>
35 #include "zed_log.h"
36
37 /*
38  * Read up to [n] bytes from [fd] into [buf].
39  * Return the number of bytes read, 0 on EOF, or -1 on error.
40  */
41 ssize_t
42 zed_file_read_n(int fd, void *buf, size_t n)
43 {
44         unsigned char *p;
45         size_t n_left;
46         ssize_t n_read;
47
48         p = buf;
49         n_left = n;
50         while (n_left > 0) {
51                 if ((n_read = read(fd, p, n_left)) < 0) {
52                         if (errno == EINTR)
53                                 continue;
54                         else
55                                 return (-1);
56
57                 } else if (n_read == 0) {
58                         break;
59                 }
60                 n_left -= n_read;
61                 p += n_read;
62         }
63         return (n - n_left);
64 }
65
66 /*
67  * Write [n] bytes from [buf] out to [fd].
68  * Return the number of bytes written, or -1 on error.
69  */
70 ssize_t
71 zed_file_write_n(int fd, void *buf, size_t n)
72 {
73         const unsigned char *p;
74         size_t n_left;
75         ssize_t n_written;
76
77         p = buf;
78         n_left = n;
79         while (n_left > 0) {
80                 if ((n_written = write(fd, p, n_left)) < 0) {
81                         if (errno == EINTR)
82                                 continue;
83                         else
84                                 return (-1);
85
86                 }
87                 n_left -= n_written;
88                 p += n_written;
89         }
90         return (n);
91 }
92
93 /*
94  * Set an exclusive advisory lock on the open file descriptor [fd].
95  * Return 0 on success, 1 if a conflicting lock is held by another process,
96  *   or -1 on error (with errno set).
97  */
98 int
99 zed_file_lock(int fd)
100 {
101         struct flock lock;
102
103         if (fd < 0) {
104                 errno = EBADF;
105                 return (-1);
106         }
107         lock.l_type = F_WRLCK;
108         lock.l_whence = SEEK_SET;
109         lock.l_start = 0;
110         lock.l_len = 0;
111
112         if (fcntl(fd, F_SETLK, &lock) < 0) {
113                 if ((errno == EACCES) || (errno == EAGAIN))
114                         return (1);
115
116                 return (-1);
117         }
118         return (0);
119 }
120
121 /*
122  * Release an advisory lock held on the open file descriptor [fd].
123  * Return 0 on success, or -1 on error (with errno set).
124  */
125 int
126 zed_file_unlock(int fd)
127 {
128         struct flock lock;
129
130         if (fd < 0) {
131                 errno = EBADF;
132                 return (-1);
133         }
134         lock.l_type = F_UNLCK;
135         lock.l_whence = SEEK_SET;
136         lock.l_start = 0;
137         lock.l_len = 0;
138
139         if (fcntl(fd, F_SETLK, &lock) < 0)
140                 return (-1);
141
142         return (0);
143 }
144
145 /*
146  * Test whether an exclusive advisory lock could be obtained for the open
147  *   file descriptor [fd].
148  * Return 0 if the file is not locked, >0 for the pid of another process
149  *   holding a conflicting lock, or -1 on error (with errno set).
150  */
151 pid_t
152 zed_file_is_locked(int fd)
153 {
154         struct flock lock;
155
156         if (fd < 0) {
157                 errno = EBADF;
158                 return (-1);
159         }
160         lock.l_type = F_WRLCK;
161         lock.l_whence = SEEK_SET;
162         lock.l_start = 0;
163         lock.l_len = 0;
164
165         if (fcntl(fd, F_GETLK, &lock) < 0)
166                 return (-1);
167
168         if (lock.l_type == F_UNLCK)
169                 return (0);
170
171         return (lock.l_pid);
172 }
173
174 /*
175  * Close all open file descriptors greater than or equal to [lowfd].
176  * Any errors encountered while closing file descriptors are ignored.
177  */
178 void
179 zed_file_close_from(int lowfd)
180 {
181         const int maxfd_def = 256;
182         int errno_bak;
183         struct rlimit rl;
184         int maxfd;
185         int fd;
186
187         errno_bak = errno;
188
189         if (getrlimit(RLIMIT_NOFILE, &rl) < 0) {
190                 maxfd = maxfd_def;
191         } else if (rl.rlim_max == RLIM_INFINITY) {
192                 maxfd = maxfd_def;
193         } else {
194                 maxfd = rl.rlim_max;
195         }
196         for (fd = lowfd; fd < maxfd; fd++)
197                 (void) close(fd);
198
199         errno = errno_bak;
200 }
201
202 /*
203  * Set the CLOEXEC flag on file descriptor [fd] so it will be automatically
204  *   closed upon successful execution of one of the exec functions.
205  * Return 0 on success, or -1 on error.
206  * FIXME: No longer needed?
207  */
208 int
209 zed_file_close_on_exec(int fd)
210 {
211         int flags;
212
213         if (fd < 0) {
214                 errno = EBADF;
215                 return (-1);
216         }
217         flags = fcntl(fd, F_GETFD);
218         if (flags == -1)
219                 return (-1);
220
221         flags |= FD_CLOEXEC;
222
223         if (fcntl(fd, F_SETFD, flags) == -1)
224                 return (-1);
225
226         return (0);
227 }
228
229 /*
230  * Create the directory [dir_name] and any missing parent directories.
231  *   Directories will be created with permissions 0755 modified by the umask.
232  * Return 0 on success, or -1 on error.
233  * FIXME: Deprecate in favor of mkdirp(). (lib/libspl/mkdirp.c)
234  */
235 int
236 zed_file_create_dirs(const char *dir_name)
237 {
238         struct stat st;
239         char dir_buf[PATH_MAX];
240         mode_t dir_mode = S_IRWXU | S_IRGRP | S_IXGRP | S_IROTH | S_IXOTH;
241         char *p;
242
243         if ((dir_name == NULL) || (dir_name[0] == '\0')) {
244                 zed_log_msg(LOG_WARNING,
245                     "Failed to create directory: no directory specified");
246                 errno = EINVAL;
247                 return (-1);
248         }
249         if (dir_name[0] != '/') {
250                 zed_log_msg(LOG_WARNING,
251                     "Failed to create directory \"%s\": not absolute path",
252                     dir_name);
253                 errno = EINVAL;
254                 return (-1);
255         }
256         /* Check if directory already exists. */
257         if (stat(dir_name, &st) == 0) {
258                 if (S_ISDIR(st.st_mode))
259                         return (0);
260
261                 errno = EEXIST;
262                 zed_log_msg(LOG_WARNING,
263                     "Failed to create directory \"%s\": %s",
264                     dir_name, strerror(errno));
265                 return (-1);
266         }
267         /* Create copy for modification. */
268         if (strlen(dir_name) >= sizeof (dir_buf)) {
269                 errno = ENAMETOOLONG;
270                 zed_log_msg(LOG_WARNING,
271                     "Failed to create directory \"%s\": %s",
272                     dir_name, strerror(errno));
273                 return (-1);
274         }
275         strncpy(dir_buf, dir_name, sizeof (dir_buf));
276
277         /* Remove trailing slashes. */
278         p = dir_buf + strlen(dir_buf) - 1;
279         while ((p > dir_buf) && (*p == '/'))
280                 *p-- = '\0';
281
282         /* Process directory components starting from the root dir. */
283         p = dir_buf;
284
285         while (1) {
286
287                 /* Skip over adjacent slashes. */
288                 while (*p == '/')
289                         p++;
290
291                 /* Advance to the next path component. */
292                 p = strchr(p, '/');
293                 if (p != NULL)
294                         *p = '\0';
295
296                 /* Create directory. */
297                 if (mkdir(dir_buf, dir_mode) < 0) {
298
299                         int mkdir_errno = errno;
300
301                         if ((mkdir_errno == EEXIST) ||
302                             (stat(dir_buf, &st) < 0) ||
303                             (!S_ISDIR(st.st_mode))) {
304                                 zed_log_msg(LOG_WARNING,
305                                     "Failed to create directory \"%s\": %s",
306                                     dir_buf, strerror(mkdir_errno));
307                                 return (-1);
308                         }
309                 }
310                 if (p == NULL)
311                         break;
312
313                 *p++ = '/';
314         }
315         return (0);
316 }