Skip to content

Instantly share code, notes, and snippets.

@lixin9311
Last active October 25, 2018 20:26
Show Gist options
  • Save lixin9311/c9508f15098b56959fd60dc4d78444cc to your computer and use it in GitHub Desktop.
Save lixin9311/c9508f15098b56959fd60dc4d78444cc to your computer and use it in GitHub Desktop.
watchdog
package main
import (
"flag"
"io"
"log"
"net"
"os"
"time"
"unsafe"
"golang.org/x/sys/unix"
)
const (
dog = "/dev/watchdog"
)
func getTimeout(fd *os.File) (int, error) {
ufd := int(fd.Fd())
return unix.IoctlGetInt(ufd, unix.WDIOC_GETTIMEOUT)
}
func setTimeout(fd *os.File, timeout int) (err error) {
ufd := int(fd.Fd())
return unix.IoctlSetInt(ufd, unix.WDIOC_SETTIMEOUT, int(uintptr(unsafe.Pointer(&timeout))))
}
func checkLastBoot(fd *os.File) (bool, error) {
ufd := int(fd.Fd())
if result, err := unix.IoctlGetInt(ufd, unix.WDIOC_GETBOOTSTATUS); err != nil {
return false, err
} else {
return result != 0, nil
}
}
func ping(fd *os.File) (err error) {
ufd := int(fd.Fd())
return unix.IoctlSetInt(ufd, unix.WDIOC_KEEPALIVE, 0)
}
func close(fd *os.File) error {
return unix.Close(int(fd.Fd()))
}
func testHost(host string) error {
if conn, err := net.DialTimeout("tcp", host, time.Second); err != nil {
return err
} else {
conn.Close()
}
return nil
}
func main() {
isClean := flag.Bool("clean", false, "Close the watchdog device. Some systems with nowayout flag does not support close.")
// isCheck := flag.Check("check", false, "Check wether the last boot was caused by watchdog")
interval := flag.Int("i", 60, "Timeout interval. Some hardware does not support change the timeout.")
ratio := flag.Float64("r", 0.5, "Ping interval ratio to the timeout.")
host := flag.String("h", "localhost:22", "The target host you want to ping.")
logFile := flag.String("l", "/tmp/watchdog.log", "log file.")
flag.Parse()
if logf, err := os.OpenFile(*logFile, os.O_APPEND|os.O_CREATE|os.O_RDWR, 0644); err != nil {
log.Printf("Failed to open log file, %v", err)
} else {
defer logf.Close()
logWriter := io.MultiWriter(os.Stderr, logf)
log.SetOutput(logWriter)
}
if _, err := os.Stat(dog); os.IsNotExist(err) {
log.Printf("HW Watchdog may not exist, please load softdog.\n")
return
}
fdog, err := os.OpenFile(dog, os.O_WRONLY, 0644)
if err != nil {
log.Printf("Failed to open watchdog, %v\n", err)
return
}
defer fdog.Close()
defer log.Println("Watchdog closed.")
if *isClean {
return
}
last, err := checkLastBoot(fdog)
if err != nil {
log.Printf("Failed to check the cause of last boot\n")
} else {
if last {
log.Printf("Last boot was casue by WATCHDOG\n")
} else {
log.Printf("Last boot was casue by RESET\n")
}
}
timeout, err := getTimeout(fdog)
if err != nil {
log.Printf("Failed to get current timeout of watchdog, %v\n", err)
return
}
log.Printf("Current timeout is [%ds].\n", timeout)
err = setTimeout(fdog, *interval)
if err != nil {
log.Printf("Failed to set timeout, %v\n", err)
log.Printf("Use default timeout [%ds].", timeout)
} else {
timeout, err = getTimeout(fdog)
if err != nil {
log.Printf("Failed to get current timeout of watchdog, %v\n", err)
return
}
log.Printf("Timeout is set to [%ds].\n", timeout)
}
duration := int(float64(timeout) * *ratio)
if duration < 1 {
duration = 1
}
log.Printf("Will ping the watchdog with interval [%ds].", duration)
for {
if err := testHost(*host); err != nil {
log.Printf("Cannot establish connetion to %s, %v", *host, err)
} else {
ping(fdog)
}
time.Sleep(time.Duration(duration) * time.Second)
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment