]> git.ipfire.org Git - thirdparty/tvheadend.git/commitdiff
spawn: do not use syslog calls in the child process
authorJaroslav Kysela <perex@perex.cz>
Sun, 16 Nov 2014 20:05:59 +0000 (21:05 +0100)
committerJaroslav Kysela <perex@perex.cz>
Sun, 16 Nov 2014 20:06:02 +0000 (21:06 +0100)
The syslog routines uses private mutex so it can cause
various crashes and other misbehaviour.

Use pipes to send messages from the child processes.

src/main.c
src/spawn.c
src/spawn.h

index c3fd56b46ee43a67b66501042d5755a1d16ac9f3..b98fdcca96f22127521ef6ce2f4285ff76f5ab86 100644 (file)
@@ -795,6 +795,8 @@ main(int argc, char **argv)
    * Initialize subsystems
    */
 
+  spawn_init();
+
   dbus_server_init(opt_dbus, opt_dbus_session);
 
   intlconv_init();
@@ -943,6 +945,7 @@ main(int argc, char **argv)
   tvhftrace("main", intlconv_done);
   tvhftrace("main", urlparse_done);
   tvhftrace("main", idnode_done);
+  tvhftrace("main", spawn_done);
 
   tvhlog(LOG_NOTICE, "STOP", "Exiting HTS Tvheadend");
   tvhlog_end();
index f3530b34235479e7cc8629057b266d984d5eddb6..a6748ea388b9f8ae80f9573902b8ca812bba762b 100644 (file)
@@ -43,12 +43,87 @@ pthread_mutex_t spawn_mutex = PTHREAD_MUTEX_INITIALIZER;
 
 static LIST_HEAD(, spawn) spawns;
 
+static char *spawn_info_buf = NULL;
+static char *spawn_error_buf = NULL;
+
+static th_pipe_t spawn_pipe_info;
+static th_pipe_t spawn_pipe_error;
+
 typedef struct spawn {
   LIST_ENTRY(spawn) link;
   pid_t pid;
   const char *name;
 } spawn_t;
 
+/*
+ *
+ */
+#define SPAWN_PIPE_READ_SIZE 4096
+
+static void
+spawn_pipe_read( th_pipe_t *p, char **_buf, int level )
+{
+  char *buf = *_buf, *s;
+  size_t len;
+  int r;
+
+  if (buf == NULL) {
+    buf = malloc(SPAWN_PIPE_READ_SIZE);
+    buf[0] = '\0';
+    buf[SPAWN_PIPE_READ_SIZE - 1] = 0;
+    *_buf = buf;
+  }
+  while (1) {
+    len = strlen(buf);
+    r = read(p->rd, buf + len, SPAWN_PIPE_READ_SIZE - 1 - len);
+    if (r < 1) {
+      if (errno == EAGAIN)
+        break;
+      if (ERRNO_AGAIN(errno))
+        continue;
+      break;
+    }
+    while ((s = strchr(buf, '\n')) != NULL) {
+      *s++ = '\0';
+      tvhlog(level, "spawn", "%s", buf);
+      memmove(buf, s, strlen(s) + 1);
+    }
+    if (strlen(buf) == SPAWN_PIPE_READ_SIZE - 1) {
+      tvherror("spawn", "pipe buffer full");
+      buf[0] = '\0';
+    }
+  }
+}
+
+static void
+spawn_pipe_write( th_pipe_t *p, const char *fmt, va_list ap )
+{
+  char buf[512];
+
+  vsnprintf(buf, sizeof(buf), fmt, ap);
+  write(p->wr, buf, strlen(buf));
+}
+
+void
+spawn_info( const char *fmt, ... )
+{
+  va_list ap;
+
+  va_start(ap, fmt);
+  spawn_pipe_write(&spawn_pipe_info, fmt, ap);
+  va_end(ap);
+}
+
+void
+spawn_error( const char *fmt, ... )
+{
+  va_list ap;
+
+  va_start(ap, fmt);
+  spawn_pipe_write(&spawn_pipe_error, fmt, ap);
+  va_end(ap);
+}
+
 /*
  * Search PATH for executable
  */
@@ -93,6 +168,9 @@ spawn_reap(char *stxt, size_t stxtlen)
   int status, res;
   spawn_t *s;
 
+  spawn_pipe_read(&spawn_pipe_info, &spawn_info_buf, LOG_INFO);
+  spawn_pipe_read(&spawn_pipe_error, &spawn_error_buf, LOG_ERR);
+
   pid = waitpid(-1, &status, WNOHANG);
   if(pid < 1)
     return -EAGAIN;
@@ -206,9 +284,8 @@ spawn_and_store_stdout(const char *prog, char *argv[], char **outp)
 
     f = open("/dev/null", O_RDWR);
     if(f == -1) {
-      syslog(LOG_ERR, 
-            "spawn: pid %d cannot open /dev/null for redirect %s -- %s",
-            getpid(), prog, strerror(errno));
+      spawn_error("pid %d cannot open /dev/null for redirect %s -- %s",
+                  getpid(), prog, strerror(errno));
       exit(1);
     }
 
@@ -216,9 +293,11 @@ spawn_and_store_stdout(const char *prog, char *argv[], char **outp)
     dup2(f, 2);
     close(f);
 
+    spawn_info("Executing \"%s\"\n", prog);
+
     execve(prog, argv, environ);
-    syslog(LOG_ERR, "spawn: pid %d cannot execute %s -- %s",
-          getpid(), prog, strerror(errno));
+    spawn_error("pid %d cannot execute %s -- %s\n",
+                getpid(), prog, strerror(errno));
     exit(1);
   }
 
@@ -264,10 +343,10 @@ spawnv(const char *prog, char *argv[])
   if(p == 0) {
     close(0);
     close(2);
-    syslog(LOG_INFO, "spawn: Executing \"%s\"", prog);
+    spawn_info("Executing \"%s\"\n", prog);
     execve(prog, argv, environ);
-    syslog(LOG_ERR, "spawn: pid %d cannot execute %s -- %s",
-          getpid(), prog, strerror(errno));
+    spawn_error("pid %d cannot execute %s -- %s\n",
+               getpid(), prog, strerror(errno));
     close(1);
     exit(1);
   }
@@ -275,3 +354,20 @@ spawnv(const char *prog, char *argv[])
   spawn_enq(prog, p);
   return 0;
 }
+
+/*
+ *
+ */
+void spawn_init(void)
+{
+  tvh_pipe(O_NONBLOCK, &spawn_pipe_info);
+  tvh_pipe(O_NONBLOCK, &spawn_pipe_error);
+}
+
+void spawn_done(void)
+{
+  tvh_pipe_close(&spawn_pipe_error);
+  tvh_pipe_close(&spawn_pipe_info);
+  free(spawn_error_buf);
+  free(spawn_info_buf);
+}
index 64e734bffe9006813cacf45a3b4969919748e122..36ae3226ca39b3c496417ed81d16c3d11b273ad0 100644 (file)
 #ifndef SPAWN_H
 #define SPAWN_H
 
+void spawn_info ( const char *fmt, ... );
+
+void spawn_error ( const char *fmt, ... );
+
 int find_exec ( const char *name, char *out, size_t len );
 
 int spawn_and_store_stdout(const char *prog, char *argv[], char **outp);
@@ -29,4 +33,8 @@ int spawn_reap(char *stxt, size_t stxtlen);
 
 void spawn_reaper(void);
 
+void spawn_init(void);
+
+void spawn_done(void);
+
 #endif /* SPAWN_H */