1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
|
/*
* This file and its contents are supplied under the terms of the
* Common Development and Distribution License ("CDDL"), version 1.0.
* You may only use this file in accordance with the terms of version
* 1.0 of the CDDL.
*
* A full copy of the text of the CDDL should have accompanied this
* source. A copy of the CDDL is also available via the Internet at
* http://www.illumos.org/license/CDDL.
*/
/*
* Copyright (c) 2014, Joyent, Inc. All rights reserved.
*/
#include <sys/inotify.h>
#include <sys/stat.h>
#include <unistd.h>
#include <errno.h>
#include <fcntl.h>
#include <strings.h>
#include <dirent.h>
int
inotify_init()
{
return (open("/dev/inotify", O_RDWR));
}
int
inotify_init1(int flags)
{
int oflags = O_RDWR;
if (flags & IN_NONBLOCK)
oflags |= O_NONBLOCK;
if (flags & IN_CLOEXEC)
oflags |= O_CLOEXEC;
return (open("/dev/inotify", oflags));
}
int
inotify_add_watch(int fd, const char *pathname, uint32_t mask)
{
inotify_addwatch_t ioc;
inotify_addchild_t cioc;
struct stat buf;
int dirfd, wd;
DIR *dir;
struct dirent *dp;
int oflags = O_RDONLY;
if (mask & IN_DONT_FOLLOW)
oflags |= O_NOFOLLOW;
if ((dirfd = open(pathname, oflags)) < 0)
return (-1);
if (fstat(dirfd, &buf) != 0) {
(void) close(dirfd);
return (-1);
}
if ((mask & IN_ONLYDIR) && !(buf.st_mode & S_IFDIR)) {
(void) close(dirfd);
errno = ENOTDIR;
return (-1);
}
bzero(&ioc, sizeof (ioc));
ioc.inaw_fd = dirfd;
ioc.inaw_mask = mask;
if ((wd = ioctl(fd, INOTIFYIOC_ADD_WATCH, &ioc)) < 0) {
(void) close(dirfd);
return (-1);
}
if (!(buf.st_mode & S_IFDIR) || !(mask & IN_CHILD_EVENTS)) {
(void) close(dirfd);
(void) ioctl(fd, INOTIFYIOC_ACTIVATE, wd);
return (wd);
}
/*
* If we have a directory and we have a mask that denotes child events,
* we need to manually add a child watch to every directory entry.
* (Because our watch is in place, it will automatically be added to
* files that are newly created after this point.)
*/
if ((dir = fdopendir(dirfd)) == NULL) {
(void) inotify_rm_watch(fd, wd);
(void) close(dirfd);
return (-1);
}
bzero(&cioc, sizeof (cioc));
cioc.inac_fd = dirfd;
while ((dp = readdir(dir)) != NULL) {
if (strcmp(dp->d_name, ".") == 0)
continue;
if (strcmp(dp->d_name, "..") == 0)
continue;
cioc.inac_name = dp->d_name;
if (ioctl(fd, INOTIFYIOC_ADD_CHILD, &cioc) != 0) {
/*
* If we get an error that indicates clear internal
* malfunctioning, we propagate the error. Otherwise
* we eat it: this could be a file that no longer
* exists or a symlink or something else that we
* can't lookup.
*/
switch (errno) {
case ENXIO:
case EFAULT:
case EBADF:
(void) closedir(dir);
(void) inotify_rm_watch(fd, wd);
return (-1);
default:
break;
}
}
}
(void) closedir(dir);
(void) ioctl(fd, INOTIFYIOC_ACTIVATE, wd);
return (wd);
}
int
inotify_rm_watch(int fd, int wd)
{
return (ioctl(fd, INOTIFYIOC_RM_WATCH, wd));
}
|