60 lines
1.3 KiB
Go
60 lines
1.3 KiB
Go
|
// Daemonization interface for Unix platforms (implementation)
|
||
|
|
||
|
//go:build !windows && !plan9 && !js
|
||
|
// +build !windows,!plan9,!js
|
||
|
|
||
|
package daemonize
|
||
|
|
||
|
import (
|
||
|
"os"
|
||
|
"syscall"
|
||
|
|
||
|
"github.com/rclone/rclone/fs"
|
||
|
)
|
||
|
|
||
|
// StartDaemon runs background twin of current process.
|
||
|
// It executes separate parts of code in child and parent processes.
|
||
|
// Returns child process pid in the parent or nil in the child.
|
||
|
// The method looks like a fork but safe for goroutines.
|
||
|
func StartDaemon(args []string) (*os.Process, error) {
|
||
|
if fs.IsDaemon() {
|
||
|
// This process is already daemonized
|
||
|
return nil, nil
|
||
|
}
|
||
|
|
||
|
env := append(os.Environ(), fs.DaemonMarkVar+"="+fs.DaemonMarkChild)
|
||
|
|
||
|
me, err := os.Executable()
|
||
|
if err != nil {
|
||
|
me = os.Args[0]
|
||
|
}
|
||
|
|
||
|
null, err := os.Open(os.DevNull)
|
||
|
if err != nil {
|
||
|
return nil, err
|
||
|
}
|
||
|
files := []*os.File{
|
||
|
null, // (0) stdin
|
||
|
null, // (1) stdout
|
||
|
null, // (2) stderr
|
||
|
}
|
||
|
sysAttr := &syscall.SysProcAttr{
|
||
|
// setsid (https://linux.die.net/man/2/setsid) in the child process will reset
|
||
|
// its process group id (PGID) to its PID thus detaching it from parent.
|
||
|
// This would make autofs fail because it detects mounting process by its PGID.
|
||
|
Setsid: false,
|
||
|
}
|
||
|
attr := &os.ProcAttr{
|
||
|
Env: env,
|
||
|
Files: files,
|
||
|
Sys: sysAttr,
|
||
|
}
|
||
|
|
||
|
daemon, err := os.StartProcess(me, args, attr)
|
||
|
if err != nil {
|
||
|
return nil, err
|
||
|
}
|
||
|
|
||
|
return daemon, nil
|
||
|
}
|