NeoMutt  2020-11-20
Teaching an old dog new tricks
DOXYGEN
monitor.h File Reference

Monitor files for changes. More...

#include <stdbool.h>
+ Include dependency graph for monitor.h:
+ This graph shows which files directly or indirectly include this file:

Go to the source code of this file.

Functions

int mutt_monitor_add (struct Mailbox *m)
 Add a watch for a mailbox. More...
 
int mutt_monitor_remove (struct Mailbox *m)
 Remove a watch for a mailbox. More...
 
int mutt_monitor_poll (void)
 Check for filesystem changes. More...
 

Variables

bool MonitorFilesChanged
 true after a monitored file has changed More...
 
bool MonitorContextChanged
 true after the current mailbox has changed More...
 

Detailed Description

Monitor files for changes.

Authors
  • Gero Treuner

This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.

You should have received a copy of the GNU General Public License along with this program. If not, see http://www.gnu.org/licenses/.

Definition in file monitor.h.

Function Documentation

◆ mutt_monitor_add()

int mutt_monitor_add ( struct Mailbox m)

Add a watch for a mailbox.

Parameters
mMailbox to watch
Return values
0success: new or already existing monitor
-1failed: no mailbox, inaccessible file, create monitor/watcher failed

If mailbox is NULL, the current mailbox (Context) is used.

Definition at line 479 of file monitor.c.

480 {
481  struct MonitorInfo info;
482  monitor_info_init(&info);
483 
484  int rc = 0;
485  enum ResolveResult desc = monitor_resolve(&info, m);
486  if (desc != RESOLVE_RES_OK_NOTEXISTING)
487  {
488  if (!m && (desc == RESOLVE_RES_OK_EXISTING))
489  MonitorContextDescriptor = info.monitor->desc;
490  rc = (desc == RESOLVE_RES_OK_EXISTING) ? 0 : -1;
491  goto cleanup;
492  }
493 
494  uint32_t mask = info.is_dir ? INOTIFY_MASK_DIR : INOTIFY_MASK_FILE;
495  if (((INotifyFd == -1) && (monitor_init() == -1)) ||
496  ((desc = inotify_add_watch(INotifyFd, info.path, mask)) == -1))
497  {
498  mutt_debug(LL_DEBUG2, "inotify_add_watch failed for '%s', errno=%d %s\n",
499  info.path, errno, strerror(errno));
500  rc = -1;
501  goto cleanup;
502  }
503 
504  mutt_debug(LL_DEBUG3, "inotify_add_watch descriptor=%d for '%s'\n", desc, info.path);
505  if (!m)
507 
508  monitor_new(&info, desc);
509 
510 cleanup:
511  monitor_info_free(&info);
512  return rc;
513 }
#define INOTIFY_MASK_FILE
Definition: monitor.c:62
Information about a monitored file.
Definition: monitor.c:94
File exists, monitor is already attached.
Definition: monitor.c:75
static int monitor_init(void)
Set up file monitoring.
Definition: monitor.c:157
static int INotifyFd
Definition: monitor.c:53
Log at debug level 2.
Definition: logging.h:41
ResolveResult
Results for the Monitor functions.
Definition: monitor.c:69
#define INOTIFY_MASK_DIR
Definition: monitor.c:61
File exists, no monitor is attached.
Definition: monitor.c:74
static void monitor_info_init(struct MonitorInfo *info)
Set up a file monitor.
Definition: monitor.c:225
static int MonitorContextDescriptor
Definition: monitor.c:59
#define mutt_debug(LEVEL,...)
Definition: logging.h:81
static struct Monitor * monitor_new(struct MonitorInfo *info, int descriptor)
Create a new file monitor.
Definition: monitor.c:205
static enum ResolveResult monitor_resolve(struct MonitorInfo *info, struct Mailbox *m)
Get the monitor for a mailbox.
Definition: monitor.c:329
static void monitor_info_free(struct MonitorInfo *info)
Shutdown a file monitor.
Definition: monitor.c:234
Log at debug level 3.
Definition: logging.h:42
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ mutt_monitor_remove()

int mutt_monitor_remove ( struct Mailbox m)

Remove a watch for a mailbox.

Parameters
mMailbox
Return values
0monitor removed (not shared)
1monitor not removed (shared)
2no monitor

If mailbox is NULL, the current mailbox (Context) is used.

Definition at line 524 of file monitor.c.

525 {
526  struct MonitorInfo info, info2;
527  int rc = 0;
528 
529  monitor_info_init(&info);
530  monitor_info_init(&info2);
531 
532  if (!m)
533  {
535  MonitorContextChanged = false;
536  }
537 
538  if (monitor_resolve(&info, m) != RESOLVE_RES_OK_EXISTING)
539  {
540  rc = 2;
541  goto cleanup;
542  }
543 
544  if (Context && Context->mailbox)
545  {
546  if (m)
547  {
548  if ((monitor_resolve(&info2, NULL) == RESOLVE_RES_OK_EXISTING) &&
549  (info.st_ino == info2.st_ino) && (info.st_dev == info2.st_dev))
550  {
551  rc = 1;
552  goto cleanup;
553  }
554  }
555  else
556  {
558  {
559  rc = 1;
560  goto cleanup;
561  }
562  }
563  }
564 
565  inotify_rm_watch(info.monitor->desc, INotifyFd);
566  mutt_debug(LL_DEBUG3, "inotify_rm_watch for '%s' descriptor=%d\n", info.path,
567  info.monitor->desc);
568 
569  monitor_delete(info.monitor);
571 
572 cleanup:
573  monitor_info_free(&info);
574  monitor_info_free(&info2);
575  return rc;
576 }
The "current" mailbox.
Definition: context.h:38
Information about a monitored file.
Definition: monitor.c:94
static void monitor_delete(struct Monitor *monitor)
Free a file monitor.
Definition: monitor.c:243
struct Mailbox * mailbox_find(const char *path)
Find the mailbox with a given path.
Definition: mailbox.c:94
char * realpath
Used for duplicate detection, context comparison, and the sidebar.
Definition: mailbox.h:84
File exists, monitor is already attached.
Definition: monitor.c:75
static int INotifyFd
Definition: monitor.c:53
struct Mailbox * mailbox
Definition: context.h:50
static void monitor_info_init(struct MonitorInfo *info)
Set up a file monitor.
Definition: monitor.c:225
bool MonitorContextChanged
true after the current mailbox has changed
Definition: monitor.c:51
static void monitor_check_free(void)
Close down file monitoring.
Definition: monitor.c:188
static int MonitorContextDescriptor
Definition: monitor.c:59
#define mutt_debug(LEVEL,...)
Definition: logging.h:81
static enum ResolveResult monitor_resolve(struct MonitorInfo *info, struct Mailbox *m)
Get the monitor for a mailbox.
Definition: monitor.c:329
static void monitor_info_free(struct MonitorInfo *info)
Shutdown a file monitor.
Definition: monitor.c:234
Log at debug level 3.
Definition: logging.h:42
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ mutt_monitor_poll()

int mutt_monitor_poll ( void  )

Check for filesystem changes.

Return values
-3unknown/unexpected events: poll timeout / fds not handled by us
-2monitor detected changes, no STDIN input
-1error (see errno)
0(1) input ready from STDIN, or (2) monitoring inactive -> no poll()

Wait for I/O ready file descriptors or signals.

MonitorFilesChanged also reflects changes to monitored files.

Only STDIN and INotify file handles currently expected/supported. More would ask for common infrastructure (sockets?).

Definition at line 397 of file monitor.c.

398 {
399  int rc = 0;
400  char buf[EVENT_BUFLEN] __attribute__((aligned(__alignof__(struct inotify_event))));
401 
402  MonitorFilesChanged = false;
403 
404  if (INotifyFd != -1)
405  {
406  int fds = poll(PollFds, PollFdsLen, MuttGetchTimeout);
407 
408  if (fds == -1)
409  {
410  rc = -1;
411  if (errno != EINTR)
412  {
413  mutt_debug(LL_DEBUG2, "poll() failed, errno=%d %s\n", errno, strerror(errno));
414  }
415  }
416  else
417  {
418  bool input_ready = false;
419  for (int i = 0; fds && (i < PollFdsCount); i++)
420  {
421  if (PollFds[i].revents)
422  {
423  fds--;
424  if (PollFds[i].fd == 0)
425  {
426  input_ready = true;
427  }
428  else if (PollFds[i].fd == INotifyFd)
429  {
430  MonitorFilesChanged = true;
431  mutt_debug(LL_DEBUG3, "file change(s) detected\n");
432  char *ptr = buf;
433  const struct inotify_event *event = NULL;
434 
435  while (true)
436  {
437  int len = read(INotifyFd, buf, sizeof(buf));
438  if (len == -1)
439  {
440  if (errno != EAGAIN)
441  {
442  mutt_debug(LL_DEBUG2, "read inotify events failed, errno=%d %s\n",
443  errno, strerror(errno));
444  }
445  break;
446  }
447 
448  while (ptr < (buf + len))
449  {
450  event = (const struct inotify_event *) ptr;
451  mutt_debug(LL_DEBUG3, "+ detail: descriptor=%d mask=0x%x\n",
452  event->wd, event->mask);
453  if (event->mask & IN_IGNORED)
454  monitor_handle_ignore(event->wd);
455  else if (event->wd == MonitorContextDescriptor)
456  MonitorContextChanged = true;
457  ptr += sizeof(struct inotify_event) + event->len;
458  }
459  }
460  }
461  }
462  }
463  if (!input_ready)
464  rc = MonitorFilesChanged ? -2 : -3;
465  }
466  }
467 
468  return rc;
469 }
#define EVENT_BUFLEN
Definition: monitor.c:64
static size_t PollFdsLen
Definition: monitor.c:56
static struct pollfd * PollFds
Definition: monitor.c:57
bool MonitorFilesChanged
true after a monitored file has changed
Definition: monitor.c:50
static int INotifyFd
Definition: monitor.c:53
Log at debug level 2.
Definition: logging.h:41
bool MonitorContextChanged
true after the current mailbox has changed
Definition: monitor.c:51
static int MonitorContextDescriptor
Definition: monitor.c:59
#define mutt_debug(LEVEL,...)
Definition: logging.h:81
static size_t PollFdsCount
Definition: monitor.c:55
Log at debug level 3.
Definition: logging.h:42
int MuttGetchTimeout
Timeout in ms for mutt_getch()
Definition: curs_lib.c:93
static int monitor_handle_ignore(int desc)
Listen for when a backup file is closed.
Definition: monitor.c:271
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

Variable Documentation

◆ MonitorFilesChanged

bool MonitorFilesChanged

true after a monitored file has changed

Definition at line 50 of file monitor.c.

◆ MonitorContextChanged

bool MonitorContextChanged

true after the current mailbox has changed

Definition at line 51 of file monitor.c.