Add watchdogd

"/sbin/watchdogd <interval> <margin>" will open /dev/watchdog, try
to set the timeout to <interval>+<margin> then write to it every
<interval> seconds to reset the watchdog.

Change-Id: I15571980cdb868ec19f20e80bf8274b32107d36d
diff --git a/init/Android.mk b/init/Android.mk
index 7dae9df..a1c1e7a 100644
--- a/init/Android.mk
+++ b/init/Android.mk
@@ -15,7 +15,8 @@
 	signal_handler.c \
 	init_parser.c \
 	ueventd.c \
-	ueventd_parser.c
+	ueventd_parser.c \
+	watchdogd.c
 
 ifeq ($(strip $(INIT_BOOTCHART)),true)
 LOCAL_SRC_FILES += bootchart.c
@@ -42,8 +43,11 @@
 
 include $(BUILD_EXECUTABLE)
 
-# Make a symlink from /sbin/ueventd to /init
-SYMLINKS := $(TARGET_ROOT_OUT)/sbin/ueventd
+# Make a symlink from /sbin/ueventd and /sbin/watchdogd to /init
+SYMLINKS := \
+	$(TARGET_ROOT_OUT)/sbin/ueventd \
+	$(TARGET_ROOT_OUT)/sbin/watchdogd
+
 $(SYMLINKS): INIT_BINARY := $(LOCAL_MODULE)
 $(SYMLINKS): $(LOCAL_INSTALLED_MODULE) $(LOCAL_PATH)/Android.mk
 	@echo "Symlink: $@ -> ../$(INIT_BINARY)"
diff --git a/init/init.c b/init/init.c
index 4f57144..48d9c9a 100755
--- a/init/init.c
+++ b/init/init.c
@@ -58,6 +58,7 @@
 #include "init_parser.h"
 #include "util.h"
 #include "ueventd.h"
+#include "watchdogd.h"
 
 #ifdef HAVE_SELINUX
 struct selabel_handle *sehandle;
@@ -863,6 +864,9 @@
     if (!strcmp(basename(argv[0]), "ueventd"))
         return ueventd_main(argc, argv);
 
+    if (!strcmp(basename(argv[0]), "watchdogd"))
+        return watchdogd_main(argc, argv);
+
     /* clear the umask */
     umask(0);
 
diff --git a/init/watchdogd.c b/init/watchdogd.c
new file mode 100644
index 0000000..fb53836
--- /dev/null
+++ b/init/watchdogd.c
@@ -0,0 +1,77 @@
+/*
+ * Copyright (C) 2012 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <errno.h>
+#include <fcntl.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include <linux/watchdog.h>
+
+#include "log.h"
+#include "util.h"
+
+#define DEV_NAME "/dev/watchdog"
+
+int watchdogd_main(int argc, char **argv)
+{
+    int fd;
+    int ret;
+    int interval = 10;
+    int margin = 10;
+    int timeout;
+
+    open_devnull_stdio();
+    klog_init();
+
+    INFO("Starting watchdogd\n");
+
+    if (argc >= 2)
+        interval = atoi(argv[1]);
+
+    if (argc >= 3)
+        margin = atoi(argv[2]);
+
+    timeout = interval + margin;
+
+    fd = open(DEV_NAME, O_RDWR);
+    if (fd < 0) {
+        ERROR("watchdogd: Failed to open %s: %s\n", DEV_NAME, strerror(errno));
+        return 1;
+    }
+
+    ret = ioctl(fd, WDIOC_SETTIMEOUT, &timeout);
+    if (ret) {
+        ERROR("watchdogd: Failed to set timeout to %d: %s\n", timeout, strerror(errno));
+        ret = ioctl(fd, WDIOC_GETTIMEOUT, &timeout);
+        if (ret) {
+            ERROR("watchdogd: Failed to get timeout: %s\n", strerror(errno));
+        } else {
+            if (timeout > margin)
+                interval = timeout - margin;
+            else
+                interval = 1;
+            ERROR("watchdogd: Adjusted interval to timeout returned by driver: timeout %d, interval %d, margin %d\n",
+                  timeout, interval, margin);
+        }
+    }
+
+    while(1) {
+        write(fd, "", 1);
+        sleep(interval);
+    }
+}
+
diff --git a/init/watchdogd.h b/init/watchdogd.h
new file mode 100644
index 0000000..8b48ab8
--- /dev/null
+++ b/init/watchdogd.h
@@ -0,0 +1,22 @@
+/*
+ * Copyright (C) 2012 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef _INIT_WATCHDOGD_H_
+#define _INIT_WATCHDOGD_H_
+
+int watchdogd_main(int argc, char **argv);
+
+#endif