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