1 /*******************************************************************************
2   Copyright (c) 2011 Dmitry Matveev <me@dmitrymatveev.co.uk>
3   Copyright (c) 2014-2018 Vladimir Kondratyev <vladimir@kondratyev.su>
4   Copyright 2008, 2013, 2014
5       The Board of Trustees of the Leland Stanford Junior University
6   Copyright (c) 2004, 2005, 2006
7       by Internet Systems Consortium, Inc. ("ISC")
8   Copyright (c) 1991, 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001,
9       2002, 2003 by The Internet Software Consortium and Rich Salz
10   SPDX-License-Identifier: MIT AND ISC
11 
12   Permission is hereby granted, free of charge, to any person obtaining a copy
13   of this software and associated documentation files (the "Software"), to deal
14   in the Software without restriction, including without limitation the rights
15   to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
16   copies of the Software, and to permit persons to whom the Software is
17   furnished to do so, subject to the following conditions:
18 
19   The above copyright notice and this permission notice shall be included in
20   all copies or substantial portions of the Software.
21 
22   THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
23   IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
24   FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
25   AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
26   LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
27   OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
28   THE SOFTWARE.
29 *******************************************************************************/
30 
31 #include "compat.h"
32 
33 #include <unistd.h> /* read, write */
34 #include <errno.h>  /* EINTR */
35 #include <stdlib.h> /* malloc */
36 #include <string.h> /* strlen */
37 #include <fcntl.h> /* fcntl */
38 #include <stdio.h>
39 #include <assert.h>
40 
41 #include <sys/types.h>
42 #include <sys/socket.h>/* send, sendmsg */
43 #include <sys/stat.h>  /* fstat */
44 #include <sys/uio.h>   /* writev */
45 
46 #include "sys/inotify.h"
47 #include "utils.h"
48 
49 /**
50  * Create a new inotify event.
51  *
52  * @param[in] wd     An associated watch's id.
53  * @param[in] mask   An inotify watch mask.
54  * @param[in] cookie Event cookie.
55  * @param[in] name   File name (may be NULL).
56  * @param[out] event_len The length of the created event, in bytes.
57  * @return A pointer to a created event on NULL on a failure.
58  **/
59 struct inotify_event*
create_inotify_event(int wd,uint32_t mask,uint32_t cookie,const char * name,size_t * event_len)60 create_inotify_event (int         wd,
61                       uint32_t    mask,
62                       uint32_t    cookie,
63                       const char *name,
64                       size_t     *event_len)
65 {
66     struct inotify_event *event = NULL;
67     size_t name_len = name ? strlen (name) + 1 : 0;
68     *event_len = sizeof (struct inotify_event) + name_len;
69     event = calloc (1, *event_len);
70 
71     if (event == NULL) {
72         perror_msg ("Failed to allocate a new inotify event [%s, %X]",
73                     name,
74                     mask);
75         return NULL;
76     }
77 
78     event->wd = wd;
79     event->mask = mask;
80     event->cookie = cookie;
81     event->len = name_len;
82 
83     if (name) {
84         strlcpy (event->name, name, name_len);
85     }
86 
87     return event;
88 }
89 
90 
91 #define SAFE_GENERIC_OP(fcn, fd, data, size, ...)              \
92     size_t total = 0;                           \
93     if (fd == -1) {                             \
94         return -1;                              \
95     }                                           \
96     while (size > 0) {                          \
97         ssize_t retval = fcn (fd, data, size, ##__VA_ARGS__);  \
98         if (retval == -1) {                     \
99             if (errno == EINTR) {               \
100                 continue;                       \
101             } else {                            \
102                 return -1;                      \
103             }                                   \
104         }                                       \
105         total += retval;                        \
106         size -= retval;                         \
107         data = (char *)data + retval;           \
108     }                                           \
109     return (ssize_t) total;
110 
111 /**
112  * EINTR-ready version of read().
113  *
114  * @param[in]  fd   A file descriptor to read from.
115  * @param[out] data A receiving buffer.
116  * @param[in]  size The number of bytes to read.
117  * @return Number of bytes which were read on success, -1 on failure.
118  **/
119 ssize_t
safe_read(int fd,void * data,size_t size)120 safe_read (int fd, void *data, size_t size)
121 {
122     SAFE_GENERIC_OP (read, fd, data, size);
123 }
124 
125 /**
126  * EINTR-ready version of write().
127  *
128  * @param[in] fd   A file descriptor to write to.
129  * @param[in] data A buffer to wtite.
130  * @param[in] size The number of bytes to write.
131  * @return Number of bytes which were written on success, -1 on failure.
132  **/
133 ssize_t
safe_write(int fd,const void * data,size_t size)134 safe_write (int fd, const void *data, size_t size)
135 {
136     SAFE_GENERIC_OP (write, fd, data, size);
137 }
138 
139 /**
140  * EINTR-ready version of send().
141  *
142  * @param[in] fd    A file descriptor to send to.
143  * @param[in] data  A buffer to send.
144  * @param[in] size  The number of bytes to send.
145  * @param[in] flags A send(3) flags.
146  * @return Number of bytes which were sent on success, -1 on failure.
147  **/
148 ssize_t
safe_send(int fd,const void * data,size_t size,int flags)149 safe_send (int fd, const void *data, size_t size, int flags)
150 {
151     SAFE_GENERIC_OP (send, fd, data, size, flags);
152 }
153 
154 /**
155  * The canonical version of this routine is maintained in the rra-c-util,
156  * which can be found at <http://www.eyrie.org/~eagle/software/rra-c-util/>.
157  */
158 #define SAFE_GENERIC_VOP(fcn, fd, iov, iovcnt, ...)			\
159 									\
160     ssize_t total, status = 0;						\
161     size_t left, offset;						\
162     int iovleft, i, count;						\
163     struct iovec *tmpiov;						\
164                                                                         \
165     /*									\
166      * Bounds-check the iovcnt argument.  This is just for our safety.  The	\
167      * system will probably impose a lower limit on iovcnt, causing the later	\
168      * writev to fail with an error we'll return.				\
169      */									\
170     if (iovcnt == 0)							\
171         return 0;							\
172     if (iovcnt < 0 || (size_t) iovcnt > SIZE_MAX / sizeof(struct iovec)) {	\
173         errno = EINVAL;							\
174         return -1;							\
175     }									\
176                                                                         \
177     /* Get a count of the total number of bytes in the iov array. */	\
178     for (total = 0, i = 0; i < iovcnt; i++)				\
179         total += iov[i].iov_len;					\
180     if (total == 0)							\
181         return 0;							\
182                                                                         \
183     /*									\
184      * First, try just writing it all out.  Most of the time this will succeed	\
185      * and save us lots of work.  Abort the write if we try ten times with no	\
186      * forward progress.						\
187      */									\
188     count = 0;								\
189     do {								\
190         if (++count > 10)						\
191             break;							\
192         status = fcn(fd, iov, iovcnt, ##__VA_ARGS__);			\
193         if (status > 0)							\
194             count = 0;							\
195     } while (status < 0 && errno == EINTR);				\
196     if (status < 0)							\
197         return -1;							\
198     if (status == total)						\
199         return total;							\
200                                                                         \
201     /*									\
202      * If we fell through to here, the first write partially succeeded.	\
203      * Figure out how far through the iov array we got, and then duplicate the	\
204      * rest of it so that we can modify it to reflect how much we manage to	\
205      * write on successive tries.					\
206      */									\
207     offset = status;							\
208     left = total - offset;						\
209     for (i = 0; offset >= (size_t) iov[i].iov_len; i++)			\
210         offset -= iov[i].iov_len;					\
211     iovleft = iovcnt - i;						\
212     assert(iovleft > 0);						\
213     tmpiov = calloc(iovleft, sizeof(struct iovec));			\
214     if (tmpiov == NULL)							\
215         return -1;							\
216     memcpy(tmpiov, iov + i, iovleft * sizeof(struct iovec));		\
217                                                                         \
218     /*									\
219      * status now contains the offset into the first iovec struct in tmpiov.	\
220      * Go into the write loop, trying to write out everything remaining at	\
221      * each point.  At the top of the loop, status will contain a count of	\
222      * bytes written out at the beginning of the set of iovec structs.		\
223      */									\
224     i = 0;								\
225     do {								\
226         if (++count > 10)						\
227             break;							\
228                                                                         \
229         /* Skip any leading data that has been written out. */		\
230         for (; offset >= (size_t) tmpiov[i].iov_len && iovleft > 0; i++) {	\
231             offset -= tmpiov[i].iov_len;				\
232             iovleft--;							\
233         }								\
234         tmpiov[i].iov_base = (char *) tmpiov[i].iov_base + offset;	\
235         tmpiov[i].iov_len -= offset;					\
236                                                                         \
237         /* Write out what's left and return success if it's all written. */	\
238         status = fcn(fd, tmpiov + i, iovleft, ##__VA_ARGS__);		\
239         if (status <= 0)						\
240             offset = 0;							\
241         else {								\
242             offset = status;						\
243             left -= offset;						\
244             count = 0;							\
245         }								\
246     } while (left > 0 && (status >= 0 || errno == EINTR));		\
247                                                                         \
248     /* We're either done or got an error; if we're done, left is now 0. */	\
249     free(tmpiov);							\
250     return (left == 0) ? total : -1;
251 
252 /**
253  * scatter-gather version of send with writev()-style parameters.
254  *
255  * @param[in] fd     A file descriptor to send to.
256  * @param[in] iov    An array of iovec buffers to wtite.
257  * @param[in] iovcnt A number of iovec buffers to write.
258  * @param[in] flags  A send(3) flags.
259  * @return Number of bytes which were written on success, -1 on failure.
260  **/
261 ssize_t
sendv(int fd,struct iovec iov[],int iovcnt,int flags)262 sendv (int fd, struct iovec iov[], int iovcnt, int flags)
263 {
264     struct msghdr msg;
265 
266     memset (&msg, 0, sizeof (msg));
267     msg.msg_iov = iov;
268     msg.msg_iovlen = iovcnt;
269 
270     return (sendmsg (fd, &msg, flags));
271 }
272 
273 /**
274  * EINTR-ready version of writev().
275  *
276  * @param[in] fd     A file descriptor to write to.
277  * @param[in] iov    An array of iovec buffers to wtite.
278  * @param[in] iovcnt A number of iovec buffers to write.
279  * @return Number of bytes which were written on success, -1 on failure.
280  **/
281 ssize_t
safe_writev(int fd,const struct iovec iov[],int iovcnt)282 safe_writev (int fd, const struct iovec iov[], int iovcnt)
283 {
284     SAFE_GENERIC_VOP (writev, fd, iov, iovcnt);
285 }
286 
287 /**
288  * EINTR-ready version of sendv().
289  *
290  * @param[in] fd     A file descriptor to send to.
291  * @param[in] iov    An array of iovec buffers to wtite.
292  * @param[in] iovcnt A number of iovec buffers to write.
293  * @param[in] flags  A send(3) flags.
294  * @return Number of bytes which were written on success, -1 on failure.
295  **/
296 ssize_t
safe_sendv(int fd,struct iovec iov[],int iovcnt,int flags)297 safe_sendv (int fd, struct iovec iov[], int iovcnt, int flags)
298 {
299     SAFE_GENERIC_VOP (sendv, fd, iov, iovcnt, flags);
300 }
301 
302 /**
303  * Check if the specified file descriptor is still opened.
304  *
305  * @param[in] fd A file descriptor to check.
306  * @return 1 if still opened, 0 if closed or an error has occured.
307  **/
308 int
is_opened(int fd)309 is_opened (int fd)
310 {
311     int ret = (fcntl (fd, F_GETFL) != -1);
312     return ret;
313 }
314 
315 /**
316  * Check if the file referenced by specified descriptor is deleted.
317  *
318  * @param[in] fd A file descriptor to check.
319  * @return 1 if deleted or error occured, 0 if hardlinks to file still exist.
320  **/
321 int
is_deleted(int fd)322 is_deleted (int fd)
323 {
324     struct stat st;
325 
326     if (fstat (fd, &st) == -1) {
327         if (errno != ENOENT) {
328             perror_msg ("fstat %d failed", fd);
329         }
330         return 1;
331     }
332 
333     return (st.st_nlink == 0);
334 }
335 
336 /**
337  * Set the FD_CLOEXEC flag of file descriptor fd if value is nonzero
338  * clear the flag if value is 0.
339  *
340  * @param[in] fd    A file descriptor to modify.
341  * @param[in] value A cloexec flag value to set.
342  * @return 0 on success, or -1 on error with errno set.
343  **/
344 int
set_cloexec_flag(int fd,int value)345 set_cloexec_flag (int fd, int value)
346 {
347     int flags = fcntl (fd, F_GETFD, 0);
348     if (flags < 0)
349         return flags;
350 
351     if (value != 0)
352         flags |= FD_CLOEXEC;
353     else
354         flags &= ~FD_CLOEXEC;
355 
356     return fcntl (fd, F_SETFD, flags);
357 }
358 
359 /*
360  * Set the O_NONBLOCK flag of file descriptor fd if value is nonzero
361  * clear the flag if value is 0.
362  *
363  * @param[in] fd    A file descriptor to modify.
364  * @param[in] value A nonblock flag value to set.
365  * @return 0 on success, or -1 on error with errno set.
366  **/
367 int
set_nonblock_flag(int fd,int value)368 set_nonblock_flag (int fd, int value)
369 {
370     int flags = fcntl (fd, F_GETFL, 0);
371     if (flags < 0)
372         return flags;
373 
374     if (value != 0)
375         flags |= O_NONBLOCK;
376     else
377         flags &= ~O_NONBLOCK;
378 
379     return fcntl (fd, F_SETFL, flags);
380 }
381 
382 /**
383  * Perform dup(2) and set the FD_CLOEXEC flag on the new file descriptor
384  *
385  * @param[in] oldd A file descriptor to duplicate.
386  * @return A new file descriptor on success, or -1 if an error occurs.
387  *      The external variable errno indicates the cause of the error.
388  **/
389 int
dup_cloexec(int oldd)390 dup_cloexec (int oldd)
391 {
392 #ifdef F_DUPFD_CLOEXEC
393     int newd = fcntl (oldd, F_DUPFD_CLOEXEC, 0);
394 #else
395     int newd = fcntl (oldd, F_DUPFD, 0);
396 
397     if ((newd != -1) && (set_cloexec_flag (newd, 1) == -1)) {
398         close (newd);
399         newd = -1;
400     }
401 #endif
402     return newd;
403 }
404 
405 /**
406  * Open directory one more time by realtive path "."
407  *
408  * @param[in] fd A file descriptor to inherit
409  * @return A new file descriptor on success, or -1 if an error occured.
410  **/
411 DIR *
fdreopendir(int oldd)412 fdreopendir (int oldd)
413 {
414     DIR *dir;
415 
416 #if (READDIR_DOES_OPENDIR == 2)
417     int openflags = O_RDONLY | O_NONBLOCK;
418 #ifdef O_CLOEXEC
419         openflags |= O_CLOEXEC;
420 #endif
421 #ifdef O_DIRECTORY
422         openflags |= O_DIRECTORY;
423 #endif
424     int fd = openat (oldd, ".", openflags);
425 #else
426     int fd = dup_cloexec (oldd);
427     /*
428      * Rewind directory content as fdopendir() does not do it for us.
429      * Note: rewinddir() right after fdopendir() is not working here
430      * due to rewinddir() bug in some versions of FreeBSD and Darwin libc.
431      */
432     lseek (fd, 0, SEEK_SET);
433 #endif
434     if (fd == -1) {
435         return NULL;
436     }
437 
438 #if (READDIR_DOES_OPENDIR == 2) && !defined(O_CLOEXEC)
439     if (set_cloexec_flag (fd, 1) == -1) {
440         close (fd);
441         return NULL;
442     }
443 #endif
444 
445     dir = fdopendir (fd);
446     if (dir == NULL) {
447         close (fd);
448     }
449 
450     return dir;
451 }
452