]> git.ipfire.org Git - thirdparty/tvheadend.git/commitdiff
epgdb: load - mmap - add SIGBUS recovery (when the file cannot be read), fixes #3238
authorJaroslav Kysela <perex@perex.cz>
Tue, 3 Nov 2015 11:57:05 +0000 (12:57 +0100)
committerJaroslav Kysela <perex@perex.cz>
Tue, 3 Nov 2015 11:57:05 +0000 (12:57 +0100)
src/epgdb.c

index f0a6b2f7064f71d7113e8bf20dfee3e269b1ce37..ad7b59089c73971dcf545ff82fb88c63e998c566 100644 (file)
@@ -21,6 +21,8 @@
 #include <sys/stat.h>
 #include <unistd.h>
 #include <pthread.h>
+#include <signal.h>
+#include <setjmp.h>
 
 #include "tvheadend.h"
 #include "queue.h"
@@ -143,6 +145,16 @@ _epgdb_v2_process( char **sect, htsmsg_t *m, epggrab_stats_t *stats )
   }
 }
 
+/*
+ * Recovery
+ */
+static sigjmp_buf epg_mmap_env;
+
+static void epg_mmap_sigbus (int sig, siginfo_t *siginfo, void *ptr)
+{
+  siglongjmp(epg_mmap_env, 1);
+}
+
 /*
  * Load data
  */
@@ -154,6 +166,7 @@ void epg_init ( void )
   uint8_t *mem, *rp;
   epggrab_stats_t stats;
   int ver = EPG_DB_VERSION;
+  struct sigaction act, oldact;
   char *sect = NULL;
 
   /* Find the right file (and version) */
@@ -168,6 +181,15 @@ void epg_init ( void )
     tvhlog(LOG_DEBUG, "epgdb", "database does not exist");
     return;
   }
+
+  memset (&act, 0, sizeof(act));
+  act.sa_sigaction = epg_mmap_sigbus;
+  act.sa_flags = SA_SIGINFO;
+  if (sigaction(SIGBUS, &act, &oldact)) {
+    tvhlog(LOG_ERR, "epgdb", "failed to install SIGBUS handler");
+    close(fd);
+    return;
+  }
   
   /* Map file to memory */
   if ( fstat(fd, &st) != 0 ) {
@@ -185,6 +207,13 @@ void epg_init ( void )
     goto end;
   }
 
+  if (sigsetjmp(epg_mmap_env, 1)) {
+    tvhlog(LOG_ERR, "epgdb", "failed to read from mapped file");
+    if (mem)
+      munmap(mem, st.st_size);
+    goto end;
+  }
+
   /* Process */
   memset(&stats, 0, sizeof(stats));
   while ( remain > 4 ) {
@@ -245,6 +274,7 @@ void epg_init ( void )
   /* Close file */
   munmap(mem, st.st_size);
 end:
+  sigaction(SIGBUS, &oldact, NULL);
   close(fd);
 }