mirror of
https://github.com/rclone/rclone.git
synced 2024-12-03 22:12:02 +01:00
89 lines
1.8 KiB
Go
89 lines
1.8 KiB
Go
// 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
|
|
}
|