rclone/vendor/github.com/sevlyar/go-daemon/oldapi/sample/dmn.go

199 lines
3.7 KiB
Go

package main
import (
"encoding/json"
"flag"
daemon "github.com/sevlyar/go-daemon/oldapi"
"log"
"os"
"syscall"
"time"
)
const (
pidFileName = "dmn.pid"
logFileName = "dmn.log"
fileMask = 0600
)
const (
ret_OK = iota
ret_ALREADYRUN
ret_PIDFERROR
ret_REBORNERROR
ret_CONFERROR
)
var (
status = flag.Bool("status", false,
`Check status of the daemon. The program immediately exits after these
checks with either a return code of 0 (Daemon Stopped) or return code
not equal to 0 (Daemon Running)`)
silent = flag.Bool("silent", false, "Don't write in stdout")
test = flag.Bool("t", false,
`Run syntax tests for configuration files only. The program
immediately exits after these syntax parsing tests with either
a return code of 0 (Syntax OK) or return code not equal to 0
(Syntax Error)`)
configFileName = flag.String("f", "dmn.conf",
`Specifies the name of the configuration file. The default is dmn.conf.
Daemon refuses to start if there is no configuration file.`)
)
var confProv = make(chan Config, 8)
func main() {
flag.Parse()
setupLogging()
conf, err := loadConfig(*configFileName)
if err != nil {
log.Println("Config error:", err)
os.Exit(ret_CONFERROR)
}
if *test {
os.Exit(ret_OK)
}
pidf := lockPidFile()
err = daemon.Reborn(027, "./")
if err != nil {
log.Println("Reborn error:", err)
os.Exit(ret_REBORNERROR)
}
confProv <- conf
go watchdog(confProv)
serveSignals()
pidf.Unlock()
}
func setupLogging() {
if daemon.WasReborn() {
file, _ := os.OpenFile(logFileName, os.O_WRONLY|os.O_CREATE|os.O_APPEND, fileMask)
daemon.RedirectStream(os.Stdout, file)
daemon.RedirectStream(os.Stderr, file)
file.Close()
log.Println("--- log ---")
} else {
log.SetFlags(0)
if *silent {
file, _ := os.OpenFile(os.DevNull, os.O_WRONLY, fileMask)
daemon.RedirectStream(os.Stdout, file)
daemon.RedirectStream(os.Stderr, file)
file.Close()
}
}
}
type Config []string
func loadConfig(path string) (config Config, err error) {
var file *os.File
file, err = os.OpenFile(path, os.O_RDONLY, 0700)
if err != nil {
return
}
defer file.Close()
config = make([]string, 0)
err = json.NewDecoder(file).Decode(&config)
if err != nil {
return
}
for _, path = range config {
if _, err = os.Stat(path); os.IsNotExist(err) {
return
}
}
return
}
func lockPidFile() *daemon.PidFile {
pidf, err := daemon.LockPidFile(pidFileName, fileMask)
if err != nil {
if err == daemon.ErrWouldBlock {
log.Println("daemon copy is already running")
os.Exit(ret_ALREADYRUN)
} else {
log.Println("pid file creation error:", err)
os.Exit(ret_PIDFERROR)
}
}
if !daemon.WasReborn() {
pidf.Unlock()
}
if *status {
os.Exit(ret_OK)
}
return pidf
}
func watchdog(confProv <-chan Config) {
states := make(map[string]time.Time)
conf := <-confProv
for {
select {
case conf = <-confProv:
default:
}
for _, path := range conf {
fi, err := os.Stat(path)
if err != nil {
log.Println(err)
continue
}
cur := fi.ModTime()
if pre, exists := states[path]; exists {
if pre != cur {
log.Printf("file %s modified at %s", path, cur)
}
}
states[path] = cur
}
time.Sleep(time.Second)
}
}
func serveSignals() {
daemon.SetHandler(termHandler, syscall.SIGTERM, syscall.SIGKILL)
daemon.SetHandler(hupHandler, syscall.SIGHUP)
err := daemon.ServeSignals()
if err != nil {
log.Println("Error:", err)
}
log.Println("--- end ---")
}
func termHandler(sig os.Signal) error {
log.Println("SIGTERM:", sig)
return daemon.ErrStop
}
func hupHandler(sig os.Signal) error {
log.Println("SIGHUP:", sig)
conf, err := loadConfig(*configFileName)
if err != nil {
log.Println("Config error:", err)
} else {
confProv <- conf
}
return nil
}