NeoMutt  2021-02-05-89-gabe350
Teaching an old dog new tricks
DOXYGEN
monitor.h File Reference
#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 481 of file monitor.c.

482 {
483  struct MonitorInfo info;
484  monitor_info_init(&info);
485 
486  int rc = 0;
487  enum ResolveResult desc = monitor_resolve(&info, m);
488  if (desc != RESOLVE_RES_OK_NOTEXISTING)
489  {
490  if (!m && (desc == RESOLVE_RES_OK_EXISTING))
491  MonitorContextDescriptor = info.monitor->desc;
492  rc = (desc == RESOLVE_RES_OK_EXISTING) ? 0 : -1;
493  goto cleanup;
494  }
495 
496  uint32_t mask = info.is_dir ? INOTIFY_MASK_DIR : INOTIFY_MASK_FILE;
497  if (((INotifyFd == -1) && (monitor_init() == -1)) ||
498  ((desc = inotify_add_watch(INotifyFd, info.path, mask)) == -1))
499  {
500  mutt_debug(LL_DEBUG2, "inotify_add_watch failed for '%s', errno=%d %s\n",
501  info.path, errno, strerror(errno));
502  rc = -1;
503  goto cleanup;
504  }
505 
506  mutt_debug(LL_DEBUG3, "inotify_add_watch descriptor=%d for '%s'\n", desc, info.path);
507  if (!m)
509 
510  monitor_new(&info, desc);
511 
512 cleanup:
513  monitor_info_free(&info);
514  return rc;
515 }
+ 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 526 of file monitor.c.

527 {
528  struct MonitorInfo info, info2;
529  int rc = 0;
530 
531  monitor_info_init(&info);
532  monitor_info_init(&info2);
533 
534  if (!m)
535  {
537  MonitorContextChanged = false;
538  }
539 
540  if (monitor_resolve(&info, m) != RESOLVE_RES_OK_EXISTING)
541  {
542  rc = 2;
543  goto cleanup;
544  }
545 
546  struct Mailbox *m_ctx = ctx_mailbox(Context);
547  if (m_ctx)
548  {
549  if (m)
550  {
551  if ((monitor_resolve(&info2, NULL) == RESOLVE_RES_OK_EXISTING) &&
552  (info.st_ino == info2.st_ino) && (info.st_dev == info2.st_dev))
553  {
554  rc = 1;
555  goto cleanup;
556  }
557  }
558  else
559  {
560  if (mailbox_find(m_ctx->realpath))
561  {
562  rc = 1;
563  goto cleanup;
564  }
565  }
566  }
567 
568  inotify_rm_watch(info.monitor->desc, INotifyFd);
569  mutt_debug(LL_DEBUG3, "inotify_rm_watch for '%s' descriptor=%d\n", info.path,
570  info.monitor->desc);
571 
572  monitor_delete(info.monitor);
574 
575 cleanup:
576  monitor_info_free(&info);
577  monitor_info_free(&info2);
578  return rc;
579 }
+ 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 399 of file monitor.c.

400 {
401  int rc = 0;
402  char buf[EVENT_BUFLEN] __attribute__((aligned(__alignof__(struct inotify_event))));
403 
404  MonitorFilesChanged = false;
405 
406  if (INotifyFd != -1)
407  {
408  int fds = poll(PollFds, PollFdsLen, MuttGetchTimeout);
409 
410  if (fds == -1)
411  {
412  rc = -1;
413  if (errno != EINTR)
414  {
415  mutt_debug(LL_DEBUG2, "poll() failed, errno=%d %s\n", errno, strerror(errno));
416  }
417  }
418  else
419  {
420  bool input_ready = false;
421  for (int i = 0; fds && (i < PollFdsCount); i++)
422  {
423  if (PollFds[i].revents)
424  {
425  fds--;
426  if (PollFds[i].fd == 0)
427  {
428  input_ready = true;
429  }
430  else if (PollFds[i].fd == INotifyFd)
431  {
432  MonitorFilesChanged = true;
433  mutt_debug(LL_DEBUG3, "file change(s) detected\n");
434  char *ptr = buf;
435  const struct inotify_event *event = NULL;
436 
437  while (true)
438  {
439  int len = read(INotifyFd, buf, sizeof(buf));
440  if (len == -1)
441  {
442  if (errno != EAGAIN)
443  {
444  mutt_debug(LL_DEBUG2, "read inotify events failed, errno=%d %s\n",
445  errno, strerror(errno));
446  }
447  break;
448  }
449 
450  while (ptr < (buf + len))
451  {
452  event = (const struct inotify_event *) ptr;
453  mutt_debug(LL_DEBUG3, "+ detail: descriptor=%d mask=0x%x\n",
454  event->wd, event->mask);
455  if (event->mask & IN_IGNORED)
456  monitor_handle_ignore(event->wd);
457  else if (event->wd == MonitorContextDescriptor)
458  MonitorContextChanged = true;
459  ptr += sizeof(struct inotify_event) + event->len;
460  }
461  }
462  }
463  }
464  }
465  if (!input_ready)
466  rc = MonitorFilesChanged ? -2 : -3;
467  }
468  }
469 
470  return rc;
471 }
+ 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 51 of file monitor.c.

◆ MonitorContextChanged

bool MonitorContextChanged

true after the current mailbox has changed

Definition at line 52 of file monitor.c.

monitor_info_free
static void monitor_info_free(struct MonitorInfo *info)
Shutdown a file monitor.
Definition: monitor.c:236
MonitorFilesChanged
bool MonitorFilesChanged
true after a monitored file has changed
Definition: monitor.c:51
monitor_delete
static void monitor_delete(struct Monitor *monitor)
Free a file monitor.
Definition: monitor.c:245
Mailbox
A mailbox.
Definition: mailbox.h:81
RESOLVE_RES_OK_NOTEXISTING
@ RESOLVE_RES_OK_NOTEXISTING
File exists, no monitor is attached.
Definition: monitor.c:75
PollFdsLen
static size_t PollFdsLen
Definition: monitor.c:57
PollFds
static struct pollfd * PollFds
Definition: monitor.c:58
LL_DEBUG3
@ LL_DEBUG3
Log at debug level 3.
Definition: logging.h:42
INotifyFd
static int INotifyFd
Definition: monitor.c:54
ctx_mailbox
struct Mailbox * ctx_mailbox(struct Context *ctx)
wrapper to get the mailbox in a Context, or NULL
Definition: context.c:429
MonitorInfo
Information about a monitored file.
Definition: monitor.c:95
INOTIFY_MASK_FILE
#define INOTIFY_MASK_FILE
Definition: monitor.c:63
monitor_init
static int monitor_init(void)
Set up file monitoring.
Definition: monitor.c:158
Context
The "current" mailbox.
Definition: context.h:38
RESOLVE_RES_OK_EXISTING
@ RESOLVE_RES_OK_EXISTING
File exists, monitor is already attached.
Definition: monitor.c:76
MuttGetchTimeout
int MuttGetchTimeout
Timeout in ms for mutt_getch()
Definition: curs_lib.c:93
mutt_debug
#define mutt_debug(LEVEL,...)
Definition: logging.h:81
ResolveResult
ResolveResult
Results for the Monitor functions.
Definition: monitor.c:70
Mailbox::realpath
char * realpath
Used for duplicate detection, context comparison, and the sidebar.
Definition: mailbox.h:84
monitor_info_init
static void monitor_info_init(struct MonitorInfo *info)
Set up a file monitor.
Definition: monitor.c:227
INOTIFY_MASK_DIR
#define INOTIFY_MASK_DIR
Definition: monitor.c:62
monitor_resolve
static enum ResolveResult monitor_resolve(struct MonitorInfo *info, struct Mailbox *m)
Get the monitor for a mailbox.
Definition: monitor.c:331
monitor_handle_ignore
static int monitor_handle_ignore(int desc)
Listen for when a backup file is closed.
Definition: monitor.c:273
monitor_check_free
static void monitor_check_free(void)
Close down file monitoring.
Definition: monitor.c:190
MonitorContextDescriptor
static int MonitorContextDescriptor
Definition: monitor.c:60
MonitorContextChanged
bool MonitorContextChanged
true after the current mailbox has changed
Definition: monitor.c:52
PollFdsCount
static size_t PollFdsCount
Definition: monitor.c:56
monitor_new
static struct Monitor * monitor_new(struct MonitorInfo *info, int descriptor)
Create a new file monitor.
Definition: monitor.c:207
EVENT_BUFLEN
#define EVENT_BUFLEN
Definition: monitor.c:65
LL_DEBUG2
@ LL_DEBUG2
Log at debug level 2.
Definition: logging.h:41
mailbox_find
struct Mailbox * mailbox_find(const char *path)
Find the mailbox with a given path.
Definition: mailbox.c:103