diff --git a/oldapi/daemon_posix.go b/oldapi/daemon_posix.go deleted file mode 100644 index 8c1f9cd..0000000 --- a/oldapi/daemon_posix.go +++ /dev/null @@ -1,88 +0,0 @@ -// Package daemon provides function to daemonization processes. -// And such as the handling of system signals and the pid-file creation. -package daemon - -import ( - "fmt" - "os" - "os/exec" - "path/filepath" - "syscall" -) - -const ( - envVarName = "_GO_DAEMON" - envVarValue = "1" -) - -// func Reborn daemonize process. Function Reborn calls ForkExec -// in the parent process and terminates him. In the child process, -// function sets umask, work dir and calls Setsid. Function sets -// for child process environment variable _GO_DAEMON=1 - the mark, -// might used for debug. -func Reborn(umask uint32, workDir string) (err error) { - - if !WasReborn() { - // parent process - fork and exec - var path string - if path, err = filepath.Abs(os.Args[0]); err != nil { - return - } - - cmd := prepareCommand(path) - - if err = cmd.Start(); err != nil { - return - } - - os.Exit(0) - } - - // child process - daemon - syscall.Umask(int(umask)) - - if len(workDir) != 0 { - if err = os.Chdir(workDir); err != nil { - return - } - } - - _, err = syscall.Setsid() - - // Do not required redirect std - // to /dev/null, this work was - // done function ForkExec - - return -} - -// func WasReborn, return true if the process has environment -// variable _GO_DAEMON=1 (child process). -func WasReborn() bool { - return os.Getenv(envVarName) == envVarValue -} - -func prepareCommand(path string) (cmd *exec.Cmd) { - - // prepare command-line arguments - cmd = exec.Command(path, os.Args[1:]...) - - // prepare environment variables - envVar := fmt.Sprintf("%s=%s", envVarName, envVarValue) - cmd.Env = append(os.Environ(), envVar) - - return -} - -// func RedirectStream redirects file s to file target. -func RedirectStream(s, target *os.File) (err error) { - - stdoutFd := int(s.Fd()) - if err = syscall.Close(stdoutFd); err != nil { - return - } - - err = syscall.Dup2(int(target.Fd()), stdoutFd) - - return -} diff --git a/oldapi/example_test.go b/oldapi/example_test.go deleted file mode 100644 index 43e8810..0000000 --- a/oldapi/example_test.go +++ /dev/null @@ -1,72 +0,0 @@ -package daemon_test - -import ( - "fmt" - "github.com/sevlyar/go-daemon/oldapi" - "log" - "os" - "syscall" -) - -func ExampleReborn() { - err := daemon.Reborn(027, "/") - if err != nil { - log.Println("Error:", err) - os.Exit(1) - } - - daemon.ServeSignals() -} - -func ExampleRedirectStream() { - file, err := os.OpenFile("/tmp/daemon-log", os.O_WRONLY|os.O_CREATE|os.O_APPEND, 0600) - if err != nil { - os.Exit(1) - } - - if err = daemon.RedirectStream(os.Stdout, file); err != nil { - os.Exit(2) - } - if err = daemon.RedirectStream(os.Stderr, file); err != nil { - os.Exit(2) - } - file.Close() - - fmt.Println("some message") - log.Println("some message") -} - -func ExampleServeSignals() { - TermHandler := func(sig os.Signal) error { - log.Println("SIGTERM:", sig) - return daemon.ErrStop - } - - HupHandler := func(sig os.Signal) error { - log.Println("SIGHUP:", sig) - return nil - } - - daemon.SetHandler(TermHandler, syscall.SIGTERM, syscall.SIGKILL) - daemon.SetHandler(HupHandler, syscall.SIGHUP) - - err := daemon.ServeSignals() - if err != nil { - log.Println("Error:", err) - } -} - -func ExampleLockPidFile() { - pidf, err := daemon.LockPidFile("name.pid", 0600) - if err != nil { - if err == daemon.ErrWouldBlock { - log.Println("daemon already exists") - } else { - log.Println("pid file creation error:", err) - } - return - } - defer pidf.Unlock() - - daemon.ServeSignals() -} diff --git a/oldapi/pid_file_posix.go b/oldapi/pid_file_posix.go deleted file mode 100644 index 94827f3..0000000 --- a/oldapi/pid_file_posix.go +++ /dev/null @@ -1,67 +0,0 @@ -package daemon - -import ( - "fmt" - "os" - "syscall" -) - -// PidFile contains information of pid-file. -type PidFile struct { - file *os.File - path string -} - -// ErrWoldBlock indicates on locking pid-file by another process. -var ErrWouldBlock = syscall.EWOULDBLOCK - -// func LockPidFile trys create and lock pid-file. -func LockPidFile(path string, perm os.FileMode) (pidf *PidFile, err error) { - var fileLen int - - var file *os.File - file, err = os.OpenFile(path, os.O_WRONLY|os.O_CREATE, perm) - if err != nil { - return - } - - if err = syscall.Flock(int(file.Fd()), syscall.LOCK_EX|syscall.LOCK_NB); err != nil { - if err == syscall.EWOULDBLOCK { - // allready locked by other process instance - file.Close() - return - } - goto SKIP - } - - if fileLen, err = fmt.Fprint(file, os.Getpid()); err != nil { - goto SKIP - } - - if err = file.Truncate(int64(fileLen)); err != nil { - goto SKIP - } - -SKIP: - if err != nil { - syscall.Unlink(path) - file.Close() - } else { - pidf = &PidFile{file, path} - } - - return -} - -// func Unlock unlocks and removes pid-file. -func (pidf *PidFile) Unlock() (err error) { - - err = syscall.Unlink(pidf.path) - err2 := pidf.file.Close() - - // return one of two errors - if err == nil { - err = err2 - } - return -} diff --git a/oldapi/sample/dmn.conf b/oldapi/sample/dmn.conf deleted file mode 100644 index f639f7d..0000000 --- a/oldapi/sample/dmn.conf +++ /dev/null @@ -1,3 +0,0 @@ -[ - "/var/log/syslog" -] diff --git a/oldapi/sample/dmn.go b/oldapi/sample/dmn.go deleted file mode 100644 index 00a35a0..0000000 --- a/oldapi/sample/dmn.go +++ /dev/null @@ -1,198 +0,0 @@ -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 -} diff --git a/oldapi/sample/dmn.sh b/oldapi/sample/dmn.sh deleted file mode 100755 index fb4c53c..0000000 --- a/oldapi/sample/dmn.sh +++ /dev/null @@ -1,63 +0,0 @@ -#!/bin/bash - - -WORK_DIR=../../../bin -PID_FILE=dmn.pid -LOG_FILE=dmn.log -DMN="./sample" -DMN_STATUS="$DMN --status --silent" - -cd $WORK_DIR -#export _GO_DAEMON=1 - -PID= -getpid() { - if $DMN_STATUS; then - echo "daemon is not running" - exit - else - PID=`cat $PID_FILE` - fi -} - -case "$1" in - start) - if $DMN; then - echo "starting daemon: OK" - else - echo "daemon return error code: $?" - fi - ;; - - stop) - getpid - kill -TERM $PID - echo "stopping daemon: OK" - ;; - - status) - getpid - echo "daemon pid: $PID" - ;; - - reload) - getpid - kill -HUP $PID - echo "reloading daemon config: OK" - ;; - - clean) - if $DMN_STATUS; then - echo "" > $LOG_FILE - echo "log cleaned" - else - echo "unable clean" - fi - ;; - - log) - cat $LOG_FILE - ;; - *) - echo "Usage: dmn.sh {start|stop|status|reload|clean|log}" -esac diff --git a/oldapi/signals.go b/oldapi/signals.go deleted file mode 100644 index f4b893c..0000000 --- a/oldapi/signals.go +++ /dev/null @@ -1,59 +0,0 @@ -package daemon - -import ( - "errors" - "os" - "os/signal" - "syscall" -) - -// ErrStop should be returned signal handler function -// for termination of handling signals. -var ErrStop = errors.New("stop serve signals") - -// SignalHandlerFunc is the interface for signal handler functions. -type SignalHandlerFunc func(sig os.Signal) (err error) - -// func SetHandler sets handler for the given signals. -// SIGTERM has the default handler, he returns ErrStop. -func SetHandler(handler SignalHandlerFunc, signals ...os.Signal) { - for _, sig := range signals { - handlers[sig] = handler - } -} - -// func ServeSignals calls handlers for system signals. -func ServeSignals() (err error) { - signals := make([]os.Signal, 0, len(handlers)) - for sig, _ := range handlers { - signals = append(signals, sig) - } - - ch := make(chan os.Signal, 8) - signal.Notify(ch, signals...) - - for sig := range ch { - err = handlers[sig](sig) - if err != nil { - break - } - } - - signal.Stop(ch) - - if err == ErrStop { - err = nil - } - - return -} - -var handlers = make(map[os.Signal]SignalHandlerFunc) - -func init() { - handlers[syscall.SIGTERM] = sigtermDefaultHandler -} - -func sigtermDefaultHandler(sig os.Signal) error { - return ErrStop -}