1 use std::{
2     io,
3     os::unix::io::{
4         AsFd,
5         AsRawFd,
6         BorrowedFd,
7         FromRawFd,
8         IntoRawFd,
9         OwnedFd,
10         RawFd,
11     },
12     path::Path,
13     sync::{
14         atomic::AtomicBool,
15         Arc,
16     }
17 };
18 
19 use inotify_sys as ffi;
20 use libc::{
21     F_GETFL,
22     F_SETFL,
23     O_NONBLOCK,
24     fcntl,
25 };
26 
27 use crate::events::Events;
28 use crate::fd_guard::FdGuard;
29 use crate::util::read_into_buffer;
30 use crate::watches::{
31     WatchDescriptor,
32     WatchMask,
33     Watches,
34 };
35 
36 
37 #[cfg(feature = "stream")]
38 use crate::stream::EventStream;
39 
40 
41 /// Idiomatic Rust wrapper around Linux's inotify API
42 ///
43 /// `Inotify` is a wrapper around an inotify instance. It generally tries to
44 /// adhere to the underlying inotify API closely, while making access to it
45 /// safe and convenient.
46 ///
47 /// Please refer to the [top-level documentation] for further details and a
48 /// usage example.
49 ///
50 /// [top-level documentation]: crate
51 #[derive(Debug)]
52 pub struct Inotify {
53     fd: Arc<FdGuard>,
54 }
55 
56 impl Inotify {
57     /// Creates an [`Inotify`] instance
58     ///
59     /// Initializes an inotify instance by calling [`inotify_init1`].
60     ///
61     /// This method passes both flags accepted by [`inotify_init1`], not giving
62     /// the user any choice in the matter, as not passing the flags would be
63     /// inappropriate in the context of this wrapper:
64     ///
65     /// - [`IN_CLOEXEC`] prevents leaking file descriptors to other processes.
66     /// - [`IN_NONBLOCK`] controls the blocking behavior of the inotify API,
67     ///   which is entirely managed by this wrapper.
68     ///
69     /// # Errors
70     ///
71     /// Directly returns the error from the call to [`inotify_init1`], without
72     /// adding any error conditions of its own.
73     ///
74     /// # Examples
75     ///
76     /// ```
77     /// use inotify::Inotify;
78     ///
79     /// let inotify = Inotify::init()
80     ///     .expect("Failed to initialize an inotify instance");
81     /// ```
82     ///
83     /// [`inotify_init1`]: inotify_sys::inotify_init1
84     /// [`IN_CLOEXEC`]: inotify_sys::IN_CLOEXEC
85     /// [`IN_NONBLOCK`]: inotify_sys::IN_NONBLOCK
init() -> io::Result<Inotify>86     pub fn init() -> io::Result<Inotify> {
87         let fd = unsafe {
88             // Initialize inotify and pass both `IN_CLOEXEC` and `IN_NONBLOCK`.
89             //
90             // `IN_NONBLOCK` is needed, because `Inotify` manages blocking
91             // behavior for the API consumer, and the way we do that is to make
92             // everything non-blocking by default and later override that as
93             // required.
94             //
95             // Passing `IN_CLOEXEC` prevents leaking file descriptors to
96             // processes executed by this process and seems to be a best
97             // practice. I don't grasp this issue completely and failed to find
98             // any authoritative sources on the topic. There's some discussion in
99             // the open(2) and fcntl(2) man pages, but I didn't find that
100             // helpful in understanding the issue of leaked file descriptors.
101             // For what it's worth, there's a Rust issue about this:
102             // https://github.com/rust-lang/rust/issues/12148
103             ffi::inotify_init1(ffi::IN_CLOEXEC | ffi::IN_NONBLOCK)
104         };
105 
106         if fd == -1 {
107             return Err(io::Error::last_os_error());
108         }
109 
110         Ok(Inotify {
111             fd: Arc::new(FdGuard {
112                 fd,
113                 close_on_drop: AtomicBool::new(true),
114             }),
115         })
116     }
117 
118     /// Gets an interface that allows adding and removing watches.
119     /// See [`Watches::add`] and [`Watches::remove`].
watches(&self) -> Watches120     pub fn watches(&self) -> Watches {
121         Watches::new(self.fd.clone())
122     }
123 
124     /// Deprecated: use `Inotify.watches().add()` instead
125     #[deprecated = "use `Inotify.watches().add()` instead"]
add_watch<P>(&mut self, path: P, mask: WatchMask) -> io::Result<WatchDescriptor> where P: AsRef<Path>126     pub fn add_watch<P>(&mut self, path: P, mask: WatchMask)
127         -> io::Result<WatchDescriptor>
128         where P: AsRef<Path>
129     {
130         self.watches().add(path, mask)
131     }
132 
133     /// Deprecated: use `Inotify.watches().remove()` instead
134     #[deprecated = "use `Inotify.watches().remove()` instead"]
rm_watch(&mut self, wd: WatchDescriptor) -> io::Result<()>135     pub fn rm_watch(&mut self, wd: WatchDescriptor) -> io::Result<()> {
136         self.watches().remove(wd)
137     }
138 
139     /// Waits until events are available, then returns them
140     ///
141     /// Blocks the current thread until at least one event is available. If this
142     /// is not desirable, please consider [`Inotify::read_events`].
143     ///
144     /// This method calls [`Inotify::read_events`] internally and behaves
145     /// essentially the same, apart from the blocking behavior. Please refer to
146     /// the documentation of [`Inotify::read_events`] for more information.
read_events_blocking<'a>(&mut self, buffer: &'a mut [u8]) -> io::Result<Events<'a>>147     pub fn read_events_blocking<'a>(&mut self, buffer: &'a mut [u8])
148         -> io::Result<Events<'a>>
149     {
150         unsafe {
151             let res = fcntl(**self.fd, F_GETFL);
152             if res == -1 {
153                 return Err(io::Error::last_os_error());
154             }
155             if fcntl(**self.fd, F_SETFL, res & !O_NONBLOCK) == -1 {
156                 return Err(io::Error::last_os_error());
157             }
158         };
159         let result = self.read_events(buffer);
160         unsafe {
161             let res = fcntl(**self.fd, F_GETFL);
162             if res == -1 {
163                 return Err(io::Error::last_os_error());
164             }
165             if fcntl(**self.fd, F_SETFL, res | O_NONBLOCK) == -1 {
166                 return Err(io::Error::last_os_error());
167             }
168         };
169 
170         result
171     }
172 
173     /// Returns one buffer's worth of available events
174     ///
175     /// Reads as many events as possible into `buffer`, and returns an iterator
176     /// over them. If no events are available, an iterator is still returned. If
177     /// you need a method that will block until at least one event is available,
178     /// please consider [`read_events_blocking`].
179     ///
180     /// Please note that inotify will merge identical successive unread events
181     /// into a single event. This means this method can not be used to count the
182     /// number of file system events.
183     ///
184     /// The `buffer` argument, as the name indicates, is used as a buffer for
185     /// the inotify events. Its contents may be overwritten.
186     ///
187     /// # Errors
188     ///
189     /// This function directly returns all errors from the call to [`read`].
190     /// In addition, [`ErrorKind::UnexpectedEof`] is returned, if the call to
191     /// [`read`] returns `0`, signaling end-of-file.
192     ///
193     /// If `buffer` is too small, this will result in an error with
194     /// [`ErrorKind::InvalidInput`]. On very old Linux kernels,
195     /// [`ErrorKind::UnexpectedEof`] will be returned instead.
196     ///
197     /// # Examples
198     ///
199     /// ```no_run
200     /// use inotify::Inotify;
201     /// use std::io::ErrorKind;
202     ///
203     /// let mut inotify = Inotify::init()
204     ///     .expect("Failed to initialize an inotify instance");
205     ///
206     /// let mut buffer = [0; 1024];
207     /// let events = loop {
208     ///     match inotify.read_events(&mut buffer) {
209     ///         Ok(events) => break events,
210     ///         Err(error) if error.kind() == ErrorKind::WouldBlock => continue,
211     ///         _ => panic!("Error while reading events"),
212     ///     }
213     /// };
214     ///
215     /// for event in events {
216     ///     // Handle event
217     /// }
218     /// ```
219     ///
220     /// [`read_events_blocking`]: Self::read_events_blocking
221     /// [`read`]: libc::read
222     /// [`ErrorKind::UnexpectedEof`]: std::io::ErrorKind::UnexpectedEof
223     /// [`ErrorKind::InvalidInput`]: std::io::ErrorKind::InvalidInput
read_events<'a>(&mut self, buffer: &'a mut [u8]) -> io::Result<Events<'a>>224     pub fn read_events<'a>(&mut self, buffer: &'a mut [u8])
225         -> io::Result<Events<'a>>
226     {
227         let num_bytes = read_into_buffer(**self.fd, buffer);
228 
229         let num_bytes = match num_bytes {
230             0 => {
231                 return Err(
232                     io::Error::new(
233                         io::ErrorKind::UnexpectedEof,
234                         "`read` return `0`, signaling end-of-file"
235                     )
236                 );
237             }
238             -1 => {
239                 let error = io::Error::last_os_error();
240                 return Err(error);
241             },
242             _ if num_bytes < 0 => {
243                 panic!("{} {} {} {} {} {}",
244                     "Unexpected return value from `read`. Received a negative",
245                     "value that was not `-1`. According to the `read` man page",
246                     "this shouldn't happen, as either `-1` is returned on",
247                     "error, `0` on end-of-file, or a positive value for the",
248                     "number of bytes read. Returned value:",
249                     num_bytes,
250                 );
251             }
252             _ => {
253                 // The value returned by `read` should be `isize`. Let's quickly
254                 // verify this with the following assignment, so we can be sure
255                 // our cast below is valid.
256                 let num_bytes: isize = num_bytes;
257 
258                 // The type returned by `read` is `isize`, and we've ruled out
259                 // all negative values with the match arms above. This means we
260                 // can safely cast to `usize`.
261                 debug_assert!(num_bytes > 0);
262                 num_bytes as usize
263             }
264         };
265 
266         Ok(Events::new(Arc::downgrade(&self.fd), buffer, num_bytes))
267     }
268 
269     /// Deprecated: use `into_event_stream()` instead, which enforces a single `Stream` and predictable reads.
270     /// Using this method to create multiple `EventStream` instances from one `Inotify` is unsupported,
271     /// as they will contend over one event source and each produce unpredictable stream contents.
272     #[deprecated = "use `into_event_stream()` instead, which enforces a single Stream and predictable reads"]
273     #[cfg(feature = "stream")]
event_stream<T>(&mut self, buffer: T) -> io::Result<EventStream<T>> where T: AsMut<[u8]> + AsRef<[u8]>,274     pub fn event_stream<T>(&mut self, buffer: T)
275         -> io::Result<EventStream<T>>
276     where
277         T: AsMut<[u8]> + AsRef<[u8]>,
278     {
279         EventStream::new(self.fd.clone(), buffer)
280     }
281 
282     /// Create a stream which collects events. Consumes the `Inotify` instance.
283     ///
284     /// Returns a `Stream` over all events that are available. This stream is an
285     /// infinite source of events.
286     ///
287     /// An internal buffer which can hold the largest possible event is used.
288     #[cfg(feature = "stream")]
into_event_stream<T>(self, buffer: T) -> io::Result<EventStream<T>> where T: AsMut<[u8]> + AsRef<[u8]>,289     pub fn into_event_stream<T>(self, buffer: T)
290         -> io::Result<EventStream<T>>
291     where
292         T: AsMut<[u8]> + AsRef<[u8]>,
293     {
294         EventStream::new(self.fd, buffer)
295     }
296 
297     /// Creates an `Inotify` instance using the file descriptor which was originally
298     /// initialized in `Inotify::init`. This is intended to be used to transform an
299     /// `EventStream` back into an `Inotify`. Do not attempt to clone `Inotify` with this.
300     #[cfg(feature = "stream")]
from_file_descriptor(fd: Arc<FdGuard>) -> Self301     pub(crate) fn from_file_descriptor(fd: Arc<FdGuard>) -> Self
302     {
303         Inotify {
304             fd,
305         }
306     }
307 
308     /// Closes the inotify instance
309     ///
310     /// Closes the file descriptor referring to the inotify instance. The user
311     /// usually doesn't have to call this function, as the underlying inotify
312     /// instance is closed automatically, when [`Inotify`] is dropped.
313     ///
314     /// # Errors
315     ///
316     /// Directly returns the error from the call to [`close`], without adding any
317     /// error conditions of its own.
318     ///
319     /// # Examples
320     ///
321     /// ```
322     /// use inotify::Inotify;
323     ///
324     /// let mut inotify = Inotify::init()
325     ///     .expect("Failed to initialize an inotify instance");
326     ///
327     /// inotify.close()
328     ///     .expect("Failed to close inotify instance");
329     /// ```
330     ///
331     /// [`close`]: libc::close
close(self) -> io::Result<()>332     pub fn close(self) -> io::Result<()> {
333         // `self` will be dropped when this method returns. If this is the only
334         // owner of `fd`, the `Arc` will also be dropped. The `Drop`
335         // implementation for `FdGuard` will attempt to close the file descriptor
336         // again, unless this flag here is cleared.
337         self.fd.should_not_close();
338 
339         match unsafe { ffi::close(**self.fd) } {
340             0 => Ok(()),
341             _ => Err(io::Error::last_os_error()),
342         }
343     }
344 }
345 
346 impl AsRawFd for Inotify {
347     #[inline]
as_raw_fd(&self) -> RawFd348     fn as_raw_fd(&self) -> RawFd {
349         self.fd.as_raw_fd()
350     }
351 }
352 
353 impl FromRawFd for Inotify {
from_raw_fd(fd: RawFd) -> Self354     unsafe fn from_raw_fd(fd: RawFd) -> Self {
355         Inotify {
356             fd: Arc::new(FdGuard::from_raw_fd(fd))
357         }
358     }
359 }
360 
361 impl IntoRawFd for Inotify {
362     #[inline]
into_raw_fd(self) -> RawFd363     fn into_raw_fd(self) -> RawFd {
364         self.fd.should_not_close();
365         self.fd.fd
366     }
367 }
368 
369 impl AsFd for Inotify {
370     #[inline]
as_fd(&self) -> BorrowedFd<'_>371     fn as_fd(&self) -> BorrowedFd<'_> {
372         self.fd.as_fd()
373     }
374 }
375 
376 impl From<Inotify> for OwnedFd {
from(fd: Inotify) -> OwnedFd377     fn from(fd: Inotify) -> OwnedFd {
378         unsafe { OwnedFd::from_raw_fd(fd.into_raw_fd()) }
379     }
380 }
381 
382 impl From<OwnedFd> for Inotify {
from(fd: OwnedFd) -> Inotify383     fn from(fd: OwnedFd) -> Inotify {
384         unsafe { Inotify::from_raw_fd(fd.into_raw_fd()) }
385     }
386 }
387