1 /* libguestfs - the guestfsd daemon
2 * Copyright (C) 2009 Red Hat Inc.
4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License as published by
6 * the Free Software Foundation; either version 2 of the License, or
7 * (at your option) any later version.
9 * This program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
14 * You should have received a copy of the GNU General Public License
15 * along with this program; if not, write to the Free Software
16 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
27 #ifdef HAVE_SYS_INOTIFY_H
28 #include <sys/inotify.h>
31 #include "../src/guestfs_protocol.h"
35 #ifdef HAVE_SYS_INOTIFY_H
36 /* Currently open inotify handle, or -1 if not opened. */
37 static int inotify_fd = -1;
39 static char inotify_buf[64*1024*1024]; /* Event buffer, [0..posn-1] is valid */
40 static size_t inotify_posn = 0;
43 /* Because inotify_init does NEED_ROOT, NEED_INOTIFY implies NEED_ROOT. */
44 #define NEED_INOTIFY(errcode) \
46 if (inotify_fd == -1) { \
47 reply_with_error ("%s: you must call 'inotify_init' first to initialize inotify", __func__); \
52 #define MQE_PATH "/proc/sys/fs/inotify/max_queued_events"
55 do_inotify_init (int max_events)
57 #ifdef HAVE_SYS_INOTIFY_H
60 NEED_ROOT (return -1);
63 reply_with_error ("inotify_init: max_events < 0");
68 fp = fopen (MQE_PATH, "w");
70 reply_with_perror (MQE_PATH);
73 fprintf (fp, "%d\n", max_events);
78 if (do_inotify_close () == -1)
81 #ifdef HAVE_INOTIFY_INIT1
82 inotify_fd = inotify_init1 (IN_NONBLOCK | IN_CLOEXEC);
83 if (inotify_fd == -1) {
84 reply_with_perror ("inotify_init");
88 inotify_fd = inotify_init ();
89 if (inotify_fd == -1) {
90 reply_with_perror ("inotify_init");
93 if (fcntl (inotify_fd, F_SETFL, O_NONBLOCK) == -1) {
94 reply_with_perror ("fcntl: O_NONBLOCK");
99 if (fcntl (inotify_fd, F_SETFD, FD_CLOEXEC) == -1) {
100 reply_with_perror ("fcntl: FD_CLOEXEC");
109 reply_with_error ("%s is not available", __func__);
115 do_inotify_close (void)
117 #ifdef HAVE_SYS_INOTIFY_H
120 if (inotify_fd == -1) {
121 reply_with_error ("inotify_close: handle is not open");
125 if (close (inotify_fd) == -1) {
126 reply_with_perror ("close");
135 reply_with_error ("%s is not available", __func__);
141 do_inotify_add_watch (const char *path, int mask)
143 #ifdef HAVE_SYS_INOTIFY_H
149 buf = sysroot_path (path);
151 reply_with_perror ("malloc");
155 r = inotify_add_watch (inotify_fd, buf, mask);
158 reply_with_perror ("inotify_add_watch: %s", path);
164 reply_with_error ("%s is not available", __func__);
170 do_inotify_rm_watch (int wd)
172 #ifdef HAVE_SYS_INOTIFY_H
175 if (inotify_rm_watch (inotify_fd, wd) == -1) {
176 reply_with_perror ("inotify_rm_watch: %d", wd);
182 reply_with_error ("%s is not available", __func__);
187 guestfs_int_inotify_event_list *
188 do_inotify_read (void)
190 #ifdef HAVE_SYS_INOTIFY_H
192 guestfs_int_inotify_event_list *ret;
196 ret = malloc (sizeof *ret);
198 reply_with_perror ("malloc");
201 ret->guestfs_int_inotify_event_list_len = 0;
202 ret->guestfs_int_inotify_event_list_val = NULL;
204 /* Read events that are available, but make sure we won't exceed
205 * maximum message size. In order to achieve this we have to
206 * guesstimate the remaining space available.
208 space = GUESTFS_MESSAGE_MAX / 2;
211 struct inotify_event *event;
215 r = read (inotify_fd, inotify_buf + inotify_posn,
216 sizeof (inotify_buf) - inotify_posn);
218 if (errno == EWOULDBLOCK || errno == EAGAIN) /* End of list. */
220 reply_with_perror ("read");
223 if (r == 0) { /* End of file - we're not expecting it. */
224 reply_with_error ("inotify_read: unexpected end of file");
230 /* Read complete events from the buffer and add them to the result. */
232 while (n < inotify_posn) {
233 guestfs_int_inotify_event *np;
234 guestfs_int_inotify_event *in;
236 event = (struct inotify_event *) &inotify_buf[n];
238 /* Have we got a complete event in the buffer? */
240 if (n + sizeof (struct inotify_event) > inotify_posn ||
241 n + sizeof (struct inotify_event) + event->len > inotify_posn)
244 #error "this code needs fixing so it works on non-GCC compilers"
247 np = realloc (ret->guestfs_int_inotify_event_list_val,
248 (ret->guestfs_int_inotify_event_list_len + 1) *
249 sizeof (guestfs_int_inotify_event));
251 reply_with_perror ("realloc");
254 ret->guestfs_int_inotify_event_list_val = np;
255 in = &ret->guestfs_int_inotify_event_list_val[ret->guestfs_int_inotify_event_list_len];
256 ret->guestfs_int_inotify_event_list_len++;
258 in->in_wd = event->wd;
259 in->in_mask = event->mask;
260 in->in_cookie = event->cookie;
263 in->in_name = strdup (event->name);
265 in->in_name = strdup (""); /* Should have optional string fields XXX. */
266 if (in->in_name == NULL) {
267 reply_with_perror ("strdup");
271 /* Estimate space used by this event in the message. */
272 space -= 16 + 4 + strlen (in->in_name) + 4;
274 /* Move pointer to next event. */
276 n += sizeof (struct inotify_event) + event->len;
278 #error "this code needs fixing so it works on non-GCC compilers"
282 /* 'n' now points to the first unprocessed/incomplete
283 * message in the buffer. Copy that to offset 0 in the buffer.
285 memmove (inotify_buf, &inotify_buf[n], inotify_posn - n);
289 /* Return the messages. */
293 xdr_free ((xdrproc_t) xdr_guestfs_int_inotify_event_list, (char *) ret);
297 reply_with_error ("%s is not available", __func__);
303 do_inotify_files (void)
305 #ifdef HAVE_SYS_INOTIFY_H
307 int size = 0, alloc = 0;
310 guestfs_int_inotify_event_list *events;
315 fp = popen ("sort -u > /tmp/inotify", "w");
317 reply_with_perror ("sort");
322 events = do_inotify_read ();
326 if (events->guestfs_int_inotify_event_list_len == 0) {
328 break; /* End of list of events. */
331 for (i = 0; i < events->guestfs_int_inotify_event_list_len; ++i) {
332 const char *name = events->guestfs_int_inotify_event_list_val[i].in_name;
335 fprintf (fp, "%s\n", name);
338 xdr_free ((xdrproc_t) xdr_guestfs_int_inotify_event_list, (char *) events);
344 fp = fopen ("/tmp/inotify", "r");
346 reply_with_perror ("/tmp/inotify");
350 while (fgets (buf, sizeof buf, fp) != NULL) {
351 int len = strlen (buf);
353 if (len > 0 && buf[len-1] == '\n')
356 if (add_string (&ret, &size, &alloc, buf) == -1) {
364 if (add_string (&ret, &size, &alloc, NULL) == -1)
367 unlink ("/tmp/inotify");
371 unlink ("/tmp/inotify");
374 reply_with_error ("%s is not available", __func__);