1 //! Monitoring API for filesystem events.
2 //!
3 //! Inotify is a Linux-only API to monitor filesystems events.
4 //!
5 //! For more documentation, please read [inotify(7)](http://man7.org/linux/man-pages/man7/inotify.7.html).
6 //!
7 //! # Examples
8 //!
9 //! Monitor all events happening in directory "test":
10 //! ```no_run
11 //! # use nix::sys::inotify::{AddWatchFlags,InitFlags,Inotify};
12 //! #
13 //! // We create a new inotify instance.
14 //! let instance = Inotify::init(InitFlags::empty()).unwrap();
15 //!
16 //! // We add a new watch on directory "test" for all events.
17 //! let wd = instance.add_watch("test", AddWatchFlags::IN_ALL_EVENTS).unwrap();
18 //!
19 //! loop {
20 //!     // We read from our inotify instance for events.
21 //!     let events = instance.read_events().unwrap();
22 //!     println!("Events: {:?}", events);
23 //! }
24 //! ```
25 
26 use libc;
27 use libc::{
28     c_char,
29     c_int,
30 };
31 use std::ffi::{OsString,OsStr,CStr};
32 use std::os::unix::ffi::OsStrExt;
33 use std::mem::size_of;
34 use std::os::unix::io::{RawFd,AsRawFd,FromRawFd};
35 use unistd::read;
36 use Result;
37 use NixPath;
38 use errno::Errno;
39 
40 libc_bitflags! {
41     /// Configuration options for [`inotify_add_watch`](fn.inotify_add_watch.html).
42     pub struct AddWatchFlags: u32 {
43         IN_ACCESS;
44         IN_MODIFY;
45         IN_ATTRIB;
46         IN_CLOSE_WRITE;
47         IN_CLOSE_NOWRITE;
48         IN_OPEN;
49         IN_MOVED_FROM;
50         IN_MOVED_TO;
51         IN_CREATE;
52         IN_DELETE;
53         IN_DELETE_SELF;
54         IN_MOVE_SELF;
55 
56         IN_UNMOUNT;
57         IN_Q_OVERFLOW;
58         IN_IGNORED;
59 
60         IN_CLOSE;
61         IN_MOVE;
62 
63         IN_ONLYDIR;
64         IN_DONT_FOLLOW;
65 
66         IN_ISDIR;
67         IN_ONESHOT;
68         IN_ALL_EVENTS;
69     }
70 }
71 
72 libc_bitflags! {
73     /// Configuration options for [`inotify_init1`](fn.inotify_init1.html).
74     pub struct InitFlags: c_int {
75         IN_CLOEXEC;
76         IN_NONBLOCK;
77     }
78 }
79 
80 /// An inotify instance. This is also a file descriptor, you can feed it to
81 /// other interfaces consuming file descriptors, epoll for example.
82 #[derive(Debug, Clone, Copy)]
83 pub struct Inotify {
84     fd: RawFd
85 }
86 
87 /// This object is returned when you create a new watch on an inotify instance.
88 /// It is then returned as part of an event once triggered. It allows you to
89 /// know which watch triggered which event.
90 #[derive(Debug, Clone, Copy, Hash, Eq, PartialEq, Ord, PartialOrd)]
91 pub struct WatchDescriptor {
92     wd: i32
93 }
94 
95 /// A single inotify event.
96 ///
97 /// For more documentation see, [inotify(7)](http://man7.org/linux/man-pages/man7/inotify.7.html).
98 #[derive(Debug)]
99 pub struct InotifyEvent {
100     /// Watch descriptor. This field corresponds to the watch descriptor you
101     /// were issued when calling add_watch. It allows you to know which watch
102     /// this event comes from.
103     pub wd: WatchDescriptor,
104     /// Event mask. This field is a bitfield describing the exact event that
105     /// occured.
106     pub mask: AddWatchFlags,
107     /// This cookie is a number that allows you to connect related events. For
108     /// now only IN_MOVED_FROM and IN_MOVED_TO can be connected.
109     pub cookie: u32,
110     /// Filename. This field exists only if the event was triggered for a file
111     /// inside the watched directory.
112     pub name: Option<OsString>
113 }
114 
115 impl Inotify {
116     /// Initialize a new inotify instance.
117     ///
118     /// Returns a Result containing an inotify instance.
119     ///
120     /// For more information see, [inotify_init(2)](http://man7.org/linux/man-pages/man2/inotify_init.2.html).
init(flags: InitFlags) -> Result<Inotify>121     pub fn init(flags: InitFlags) -> Result<Inotify> {
122         let res = Errno::result(unsafe {
123             libc::inotify_init1(flags.bits())
124         });
125 
126         res.map(|fd| Inotify { fd })
127     }
128 
129     /// Adds a new watch on the target file or directory.
130     ///
131     /// Returns a watch descriptor. This is not a File Descriptor!
132     ///
133     /// For more information see, [inotify_add_watch(2)](http://man7.org/linux/man-pages/man2/inotify_add_watch.2.html).
add_watch<P: ?Sized + NixPath>(&self, path: &P, mask: AddWatchFlags) -> Result<WatchDescriptor>134     pub fn add_watch<P: ?Sized + NixPath>(&self,
135                                           path: &P,
136                                           mask: AddWatchFlags)
137                                             -> Result<WatchDescriptor>
138     {
139         let res = path.with_nix_path(|cstr| {
140             unsafe {
141                 libc::inotify_add_watch(self.fd, cstr.as_ptr(), mask.bits())
142             }
143         })?;
144 
145         Errno::result(res).map(|wd| WatchDescriptor { wd })
146     }
147 
148     /// Removes an existing watch using the watch descriptor returned by
149     /// inotify_add_watch.
150     ///
151     /// Returns an EINVAL error if the watch descriptor is invalid.
152     ///
153     /// For more information see, [inotify_rm_watch(2)](http://man7.org/linux/man-pages/man2/inotify_rm_watch.2.html).
154     #[cfg(target_os = "linux")]
rm_watch(&self, wd: WatchDescriptor) -> Result<()>155     pub fn rm_watch(&self, wd: WatchDescriptor) -> Result<()> {
156         let res = unsafe { libc::inotify_rm_watch(self.fd, wd.wd) };
157 
158         Errno::result(res).map(drop)
159     }
160 
161     #[cfg(target_os = "android")]
rm_watch(&self, wd: WatchDescriptor) -> Result<()>162     pub fn rm_watch(&self, wd: WatchDescriptor) -> Result<()> {
163         let res = unsafe { libc::inotify_rm_watch(self.fd, wd.wd as u32) };
164 
165         Errno::result(res).map(drop)
166     }
167 
168     /// Reads a collection of events from the inotify file descriptor. This call
169     /// can either be blocking or non blocking depending on whether IN_NONBLOCK
170     /// was set at initialization.
171     ///
172     /// Returns as many events as available. If the call was non blocking and no
173     /// events could be read then the EAGAIN error is returned.
read_events(&self) -> Result<Vec<InotifyEvent>>174     pub fn read_events(&self) -> Result<Vec<InotifyEvent>> {
175         let header_size = size_of::<libc::inotify_event>();
176         let mut buffer = [0u8; 4096];
177         let mut events = Vec::new();
178         let mut offset = 0;
179 
180         let nread = read(self.fd, &mut buffer)?;
181 
182         while (nread - offset) >= header_size {
183             let event = unsafe {
184                 &*(
185                     buffer
186                         .as_ptr()
187                         .offset(offset as isize) as *const libc::inotify_event
188                 )
189             };
190 
191             let name = match event.len {
192                 0 => None,
193                 _ => {
194                     let ptr = unsafe {
195                         buffer
196                             .as_ptr()
197                             .offset(offset as isize + header_size as isize)
198                             as *const c_char
199                     };
200                     let cstr = unsafe { CStr::from_ptr(ptr) };
201 
202                     Some(OsStr::from_bytes(cstr.to_bytes()).to_owned())
203                 }
204             };
205 
206             events.push(InotifyEvent {
207                 wd: WatchDescriptor { wd: event.wd },
208                 mask: AddWatchFlags::from_bits_truncate(event.mask),
209                 cookie: event.cookie,
210                 name
211             });
212 
213             offset += header_size + event.len as usize;
214         }
215 
216         Ok(events)
217     }
218 }
219 
220 impl AsRawFd for Inotify {
as_raw_fd(&self) -> RawFd221     fn as_raw_fd(&self) -> RawFd {
222         self.fd
223     }
224 }
225 
226 impl FromRawFd for Inotify {
from_raw_fd(fd: RawFd) -> Self227     unsafe fn from_raw_fd(fd: RawFd) -> Self {
228         Inotify { fd }
229     }
230 }
231