Index: ChangeLog
===================================================================
--- ChangeLog	(revision 5618)
+++ ChangeLog	(revision 5619)
@@ -4,4 +4,5 @@
 	* Converted roard's protocol-irc plugin to CPI (Closes: #295)
 	* Updated protocol magic numbers (See: #262)
+	* Implemented watchdog (Closes: #291)
 
 v. 1.0beta4 - Mon Aug 06 2012 16:43 CEST
Index: include/libroar/libroar.h
===================================================================
--- include/libroar/libroar.h	(revision 5517)
+++ include/libroar/libroar.h	(revision 5619)
@@ -188,4 +188,5 @@
 #include "asyncctl.h"
 #include "kstore.h"
+#include "watchdog.h"
 
 // some basic macros:
@@ -245,4 +246,6 @@
  ROAR_FATAL_ERROR_MEMORY_DOUBLE_FREE,
 #define ROAR_FATAL_ERROR_MEMORY_DOUBLE_FREE ROAR_FATAL_ERROR_MEMORY_DOUBLE_FREE
+ ROAR_FATAL_ERROR_WATCHDOG,
+#define ROAR_FATAL_ERROR_WATCHDOG ROAR_FATAL_ERROR_WATCHDOG
 
  ROAR_FATAL_ERROR_EOL
Index: include/libroar/roarfeatures.h
===================================================================
--- include/libroar/roarfeatures.h	(revision 5609)
+++ include/libroar/roarfeatures.h	(revision 5619)
@@ -65,4 +65,5 @@
 #define ROAR_FT_FEATURE_COMMON_PROTO /* see #257 */
 #define ROAR_FT_FEATURE_SELECTOR_HANDLING /* see #285 */
+#define ROAR_FT_FEATURE_WATCHDOG /* see #291 */
 
 // libroar2 features:
Index: include/libroar/watchdog.h
===================================================================
--- include/libroar/watchdog.h	(revision 5619)
+++ include/libroar/watchdog.h	(revision 5619)
@@ -0,0 +1,79 @@
+//watchdog.h:
+
+/*
+ *      Copyright (C) Philipp 'ph3-der-loewe' Schafft - 2012
+ *
+ *  This file is part of libroar a part of RoarAudio,
+ *  a cross-platform sound system for both, home and professional use.
+ *  See README for details.
+ *
+ *  This file is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License version 3
+ *  as published by the Free Software Foundation.
+ *
+ *  libroar 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 software; see the file COPYING.  If not, write to
+ *  the Free Software Foundation, 51 Franklin Street, Fifth Floor,
+ *  Boston, MA 02110-1301, USA.
+ *
+ *  NOTE for everyone want's to change something and send patches:
+ *  read README and HACKING! There a addition information on
+ *  the license of this document you need to read before you send
+ *  any patches.
+ *
+ *  NOTE for uses of non-GPL (LGPL,...) software using libesd, libartsc
+ *  or libpulse*:
+ *  The libs libroaresd, libroararts and libroarpulse link this lib
+ *  and are therefore GPL. Because of this it may be illigal to use
+ *  them with any software that uses libesd, libartsc or libpulse*.
+ */
+
+#ifndef _LIBROARWATCHDOG_H_
+#define _LIBROARWATCHDOG_H_
+
+#include "libroar.h"
+
+enum roar_watchdog_event {
+ ROAR_WATCHDOG_START = 0,
+ ROAR_WATCHDOG_STOP,
+ ROAR_WATCHDOG_TRIGGER,
+ ROAR_WATCHDOG_TICK,
+ ROAR_WATCHDOG_TIMEOUT,
+ ROAR_WATCHDOG_DOUBLETIMEOUT,
+};
+
+#define ROAR_WATCHDOG_CONF_DEFAULTS          -1
+#define ROAR_WATCHDOG_CONF_RESTART           -2
+#define ROAR_WATCHDOG_CONF_STOPPABLE         0x0001
+#define ROAR_WATCHDOG_CONF_CLOCK_INTERNAL    0x0000
+#define ROAR_WATCHDOG_CONF_CLOCK_EXTERNAL    0x0010
+#define ROAR_WATCHDOG_CONF_CLOCK_ROUND_DOWN  0x0000
+#define ROAR_WATCHDOG_CONF_CLOCK_ROUND_UP    0x0020
+#define ROAR_WATCHDOG_CONF_EVENTS_ONLY_MAJOR 0x0000
+#define ROAR_WATCHDOG_CONF_EVENTS_ALSO_MINOR 0x0100
+
+// start the watchdog.
+// timeout is in ms.
+int roar_watchdog_start(int config, int_least32_t timeout, int (*callback)(enum roar_watchdog_event event));
+
+// Get timeout for watchdog.
+// This may be diffrent from the requested time.
+int_least32_t roar_watchdog_gettime(void);
+
+// stop it, if stopping is enabled.
+int roar_watchdog_stop(void);
+
+// Trigger the watchdog to show that we are still alive.
+int roar_watchdog_trigger(void);
+
+// Trigger the watchdog clock. This is only used if configured to run with external clock source.
+int roar_watchdog_tick(void);
+
+#endif
+
+//ll
Index: libroar/Makefile
===================================================================
--- libroar/Makefile	(revision 5529)
+++ libroar/Makefile	(revision 5619)
@@ -11,5 +11,5 @@
 PASSWORD=passwordapi.o pinentry.o sshaskpass.o
 CRYPTO=crypto.o random.o $(HASHES) crc.o
-OBJS=libroar.o config.o debug.o error.o basic.o stream.o client.o simple.o auth.o socket.o ctl.o buffer.o meta.o file.o acl.o cdrom.o $(PASSWORD) $(VIO) stack.o slp.o nnode.o roardl.o plugincontainer.o roarx11.o beep.o proto.o env.o keyval.o vs.o ltm.o notify.o notify_proxy.o asyncctl.o enumdev.o serverinfo.o $(CRYPTO) authfile.o caps.o roarfloat.o base64.o trap.o memmgr.o time.o kstore.o uuid.o
+OBJS=libroar.o config.o debug.o error.o basic.o stream.o client.o simple.o auth.o socket.o ctl.o buffer.o meta.o file.o acl.o cdrom.o $(PASSWORD) $(VIO) stack.o slp.o nnode.o roardl.o plugincontainer.o roarx11.o beep.o proto.o env.o keyval.o vs.o ltm.o notify.o notify_proxy.o asyncctl.o enumdev.o serverinfo.o $(CRYPTO) authfile.o caps.o roarfloat.o base64.o trap.o memmgr.o time.o kstore.o uuid.o watchdog.o
 
 #DEFINES        = -DDEBUG
Index: libroar/basic.c
===================================================================
--- libroar/basic.c	(revision 5608)
+++ libroar/basic.c	(revision 5619)
@@ -91,4 +91,6 @@
   return -1;
  } else if ( r == 0 ) { // we are the child
+  roar_watchdog_stop();
+
   close(socks[0]);
 
@@ -113,5 +115,5 @@
   // we are still alive?
   ROAR_ERR("_start_server(*): alive after exec(), that's bad!");
-  _exit(1);
+  ROAR_U_EXIT(1);
  } else { // we are the parent
   close(socks[1]);
Index: libroar/cdrom.c
===================================================================
--- libroar/cdrom.c	(revision 5381)
+++ libroar/cdrom.c	(revision 5619)
@@ -36,5 +36,5 @@
 #include "libroar.h"
 
-#define ROAR_CDROM_ERROR_NORETURN(format, args...) ROAR_ERR(format, ## args); _exit(3)
+#define ROAR_CDROM_ERROR_NORETURN(format, args...) ROAR_ERR(format, ## args); ROAR_U_EXIT(3)
 
 #if BYTE_ORDER == BIG_ENDIAN
Index: libroar/libroar.c
===================================================================
--- libroar/libroar.c	(revision 5390)
+++ libroar/libroar.c	(revision 5619)
@@ -107,5 +107,5 @@
  struct timespec left;
 
- if ( t > (uint_least32_t)1000000 ) {
+ if ( t >= (uint_least32_t)1000000 ) {
   tv.tv_sec  = t/(uint_least32_t)1000000;
   t         -= tv.tv_sec*(uint_least32_t)1000000;
@@ -321,4 +321,7 @@
     errname = "Memory double freed";
    break;
+  case ROAR_FATAL_ERROR_WATCHDOG:
+    errname = "Watchdog Timeout";
+   break;
   default:
     errname = "<unknown error code, BAD>";
@@ -332,4 +335,7 @@
 #endif
  abort();
+#ifdef ROAR_HAVE_U_EXIT
+ ROAR_U_EXIT(1);
+#endif
 
  while(1);
Index: libroar/pinentry.c
===================================================================
--- libroar/pinentry.c	(revision 5381)
+++ libroar/pinentry.c	(revision 5619)
@@ -99,4 +99,6 @@
    break;
   case 0:
+    roar_watchdog_stop();
+
     close(in[0]);
     close(out[1]);
@@ -105,12 +107,12 @@
 
     if ( dup2(out[0], ROAR_STDIN) == -1 )
-     _exit(1);
+     ROAR_U_EXIT(1);
 
     if ( dup2(in[1], ROAR_STDOUT) == -1 )
-     _exit(1);
+     ROAR_U_EXIT(1);
 
     execlp(ROAR_HAVE_BIN_PINENTRY, "RoarAudio", "--display", display, "--ttytype", term, "--ttyname", tty, NULL);
 
-    _exit(1);
+    ROAR_U_EXIT(1);
    break;
  }
Index: libroar/socket.c
===================================================================
--- libroar/socket.c	(revision 5554)
+++ libroar/socket.c	(revision 5619)
@@ -1176,4 +1176,6 @@
   return -1;
  } else if ( r == 0 ) { // we are the child
+  roar_watchdog_stop();
+
   close(socks[0]);
 
@@ -1189,5 +1191,5 @@
   // we are still alive?
   ROAR_ERR("roar_socket_open_ssh(*): alive after exec(), that's bad!");
-  _exit(1);
+  ROAR_U_EXIT(1);
  } else { // we are the parent
   close(socks[1]);
Index: libroar/vio_cmd.c
===================================================================
--- libroar/vio_cmd.c	(revision 5405)
+++ libroar/vio_cmd.c	(revision 5619)
@@ -172,4 +172,6 @@
    break;
   case 0:
+    roar_watchdog_stop();
+
     close(in[0]);
     close(out[1]);
@@ -178,12 +180,12 @@
 
     if ( dup2(out[0], ROAR_STDIN) == -1 )
-     _exit(1);
+     ROAR_U_EXIT(1);
 
     if ( dup2(in[1], ROAR_STDOUT) == -1 )
-     _exit(1);
+     ROAR_U_EXIT(1);
 
     execlp("/bin/sh", "/bin/sh", "-c", child->cmd, (_LIBROAR_GOOD_CAST char*)NULL);
 
-    _exit(1);
+    ROAR_U_EXIT(1);
    break;
  }
Index: libroar/watchdog.c
===================================================================
--- libroar/watchdog.c	(revision 5619)
+++ libroar/watchdog.c	(revision 5619)
@@ -0,0 +1,225 @@
+//watchdog.c:
+
+/*
+ *      Copyright (C) Philipp 'ph3-der-loewe' Schafft - 2012
+ *
+ *  This file is part of libroar a part of RoarAudio,
+ *  a cross-platform sound system for both, home and professional use.
+ *  See README for details.
+ *
+ *  This file is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License version 3
+ *  as published by the Free Software Foundation.
+ *
+ *  libroar 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 software; see the file COPYING.  If not, write to
+ *  the Free Software Foundation, 51 Franklin Street, Fifth Floor,
+ *  Boston, MA 02110-1301, USA.
+ *
+ *  NOTE for everyone want's to change something and send patches:
+ *  read README and HACKING! There a addition information on
+ *  the license of this document you need to read before you send
+ *  any patches.
+ *
+ *  NOTE for uses of non-GPL (LGPL,...) software using libesd, libartsc
+ *  or libpulse*:
+ *  The libs libroaresd, libroararts and libroarpulse link this lib
+ *  and are therefore GPL. Because of this it may be illigal to use
+ *  them with any software that uses libesd, libartsc or libpulse*.
+ */
+
+#include "libroar.h"
+
+#define _CONF_DEFAULT ROAR_WATCHDOG_CONF_STOPPABLE|ROAR_WATCHDOG_CONF_CLOCK_INTERNAL;
+static int _config = _CONF_DEFAULT;
+static int _triggered = 0;
+static int _running = 0;
+static int_least32_t _timeout = 10000; // 10 sec.
+static int (*_callback)(enum roar_watchdog_event event) = NULL;
+static pid_t _starter_pid = 0;
+
+#ifdef ROAR_HAVE_ALARM
+static void _on_sig_alarm (int signum) {
+ (void)signum;
+ signal(SIGALRM,  _on_sig_alarm);
+ alarm(_timeout/1000);
+ roar_watchdog_tick();
+}
+#endif
+
+static int __event_handler(enum roar_watchdog_event event) {
+ int ret;
+
+ if ( event == ROAR_WATCHDOG_DOUBLETIMEOUT ) {
+  ROAR_ERR("Watchdog event: DoubleTimeOut. Bad. Terminating program.");
+  // panic...
+  roar_panic(ROAR_FATAL_ERROR_WATCHDOG, NULL);
+ } else if ( event == ROAR_WATCHDOG_TIMEOUT ) {
+  ROAR_ERR("Watchdog event: TimeOut. Cleaning Up.");
+ }
+
+ if ( _callback != NULL ) {
+  if ( (_config & ROAR_WATCHDOG_CONF_EVENTS_ALSO_MINOR) ||
+       event == ROAR_WATCHDOG_TIMEOUT                   ||
+       event == ROAR_WATCHDOG_START                     ||
+       event == ROAR_WATCHDOG_STOP ) {
+   ret = _callback(event);
+   if ( ret == -1 && event == ROAR_WATCHDOG_TIMEOUT )
+    __event_handler(ROAR_WATCHDOG_DOUBLETIMEOUT);
+  }
+ }
+
+ if ( event == ROAR_WATCHDOG_TIMEOUT ) {
+  ROAR_ERR("Watchdog event: TimeOut. Terminating program.");
+  roar_panic(ROAR_FATAL_ERROR_WATCHDOG, NULL);
+ }
+
+ return 0;
+}
+
+// start the watchdog.
+// timeout is in ms.
+int roar_watchdog_start(int config, int_least32_t timeout, int (*callback)(enum roar_watchdog_event event)) {
+ int ret = -1;
+
+ if ( config == ROAR_WATCHDOG_CONF_DEFAULTS ) {
+  config = _CONF_DEFAULT;
+ } else if ( config == ROAR_WATCHDOG_CONF_RESTART ) {
+  config = _config;
+  if ( timeout == -1 )
+   timeout = _timeout;
+  if ( callback == NULL )
+   callback = _callback;
+ }
+
+ if ( timeout < 1 ) {
+  roar_err_set(ROAR_ERROR_CAUSALITY);
+  return -1;
+ }
+
+ if ( _running ) {
+  if ( _config & ROAR_WATCHDOG_CONF_STOPPABLE ) {
+   if ( roar_watchdog_stop() == -1 )
+    return -1;
+  } else {
+   roar_err_set(ROAR_ERROR_BUSY);
+   return -1;
+  }
+ }
+
+ if ( !(config & ROAR_WATCHDOG_CONF_CLOCK_EXTERNAL) ) {
+#ifdef ROAR_HAVE_ALARM
+  if ( config & ROAR_WATCHDOG_CONF_CLOCK_ROUND_UP ) {
+   if ( timeout % 1000 )
+    timeout += 1000;
+  }
+
+  timeout /= 1000;
+  if ( timeout == 0 )
+   timeout = 1;
+
+  timeout *= 1000;
+#else
+  roar_err_set(ROAR_ERROR_NOSYS);
+  return -1;
+#endif
+ }
+
+ _config   = config;
+ _timeout  = timeout;
+ _callback = callback;
+
+ if ( config & ROAR_WATCHDOG_CONF_CLOCK_EXTERNAL ) {
+  ret = __event_handler(ROAR_WATCHDOG_START);
+#ifdef ROAR_HAVE_ALARM
+ } else {
+  signal(SIGALRM,  _on_sig_alarm);
+  alarm(_timeout/1000);
+  ret = 0;
+#endif
+ }
+
+ if ( ret == -1 )
+  return -1;
+
+ _running = 1;
+ _starter_pid = getpid();
+ return 0;
+}
+
+// Get timeout for watchdog.
+// This may be diffrent from the requested time.
+int_least32_t roar_watchdog_gettime(void) {
+ if ( !_running ) {
+  roar_err_set(ROAR_ERROR_NOENT);
+  return -1;
+ }
+ return _timeout;
+}
+
+// stop it, if stopping is enabled.
+int roar_watchdog_stop(void) {
+ int ret;
+
+ if ( !_running )
+  return 0;
+
+ // test if we are allowed to stop the watchdog.
+ // In addition always allow to stop it in childs.
+ if ( !(_config & ROAR_WATCHDOG_CONF_STOPPABLE) && _starter_pid == getpid() ) {
+  ROAR_WARN("roar_watchdog_stop(void): Software tries to stop watchdog but is not allowed to.");
+  roar_err_set(ROAR_ERROR_PERM);
+  return -1;
+ }
+
+
+#ifdef ROAR_HAVE_ALARM
+ if ( !(_config & ROAR_WATCHDOG_CONF_CLOCK_EXTERNAL) ) {
+  alarm(0);
+  _running = 0;
+ }
+#endif
+
+ ret = __event_handler(ROAR_WATCHDOG_STOP);
+ if ( ret != -1 )
+  _running = 0;
+
+ return ret;
+}
+
+// Trigger the watchdog to show that we are still alive.
+int roar_watchdog_trigger(void) {
+ if ( !_running )
+  return 0;
+
+ _triggered = 1;
+ return __event_handler(ROAR_WATCHDOG_TRIGGER);
+}
+
+// Trigger the watchdog clock. This is only used if configured to run with external clock source.
+int roar_watchdog_tick(void) {
+ int ret = 0;
+
+ ROAR_DBG("roar_watchdog_tick(void) = ?");
+
+ if ( !_running )
+  return 0;
+
+ if ( _triggered == 0 ) {
+  _triggered = -1;
+  ret = __event_handler(ROAR_WATCHDOG_TIMEOUT);
+ } else if ( _triggered == -1 ) {
+  ret = __event_handler(ROAR_WATCHDOG_DOUBLETIMEOUT);
+ } else {
+  _triggered = 0;
+ }
+
+ return ret;
+}
+
+//ll
Index: roard/lib.c
===================================================================
--- roard/lib.c	(revision 5586)
+++ roard/lib.c	(revision 5619)
@@ -34,5 +34,5 @@
  ROAR_WARN("lib_run_bg(cmd='%s', ...): This function should never be called. Contact devels.");
 
- child = fork();
+ child = roar_fork(NULL);
 
  if ( child == -1 ) {
@@ -47,5 +47,9 @@
 
  // we are the child.
- // first we need to close a lot of open files!
+
+ // first stop the watchdog.
+ roar_watchdog_stop();
+
+ // then we need to close a lot of open files!
 
  // before we do this we need to keep backups of our handles:
Index: roard/loop.c
===================================================================
--- roard/loop.c	(revision 5586)
+++ roard/loop.c	(revision 5619)
@@ -62,4 +62,6 @@
 
   ROAR_DBG("main_loop(*): looping...");
+
+  roar_watchdog_trigger();
 
 #ifdef ROAR_SUPPORT_LISTEN
Index: roard/roard.c
===================================================================
--- roard/roard.c	(revision 5592)
+++ roard/roard.c	(revision 5619)
@@ -224,4 +224,6 @@
         "                         give multible times for being more realtime\n"
         " --memlock LEVEL       - Set default memory locking level to LEVEL\n"
+        " --watchdog            - Enable watchdog\n"
+        " --watchdog-time TIME  - Set watchdog time to TIME (in ms)\n"
 #ifdef ROAR_HAVE_CHROOT
         " --chroot DIR          - chroots to the given dir\n"
@@ -1428,4 +1430,5 @@
  int    daemon       = 0;
 #endif
+ int_least32_t watchdog_time = 0; // -1: default, 0: disabled, > 0: user set time.
  int    realtime     = 0;
  int    sysclocksync = 0;
@@ -1700,4 +1703,10 @@
    _CKHAVEARGS(1);
    g_config->memlock_level = memlock_str2level(argv[++i]);
+  } else if ( strcmp(k, "--watchdog") == 0 ) {
+   if ( watchdog_time == 0 )
+    watchdog_time = -1;
+  } else if ( strcmp(k, "--watchdog-time") == 0 ) {
+   _CKHAVEARGS(1);
+    watchdog_time = atoi(argv[++i]);
   } else if ( strcmp(k, "--chroot") == 0 ) {
    _CKHAVEARGS(1);
@@ -2581,5 +2590,5 @@
   close(ROAR_STDERR);
 
-  if ( fork() )
+  if ( roar_fork(NULL) )
    ROAR_U_EXIT(0);
 
@@ -2591,4 +2600,10 @@
  }
 #endif
+
+ if ( watchdog_time ) {
+  if ( watchdog_time == -1 )
+   watchdog_time = 5000;
+  roar_watchdog_start(ROAR_WATCHDOG_CONF_DEFAULTS, watchdog_time, NULL);
+ }
 
 #if defined(ROAR_HAVE_SETUID) && defined(ROAR_HAVE_IO_POSIX)
