約1年前、小さなネットワークサービスを実装するLinuxデーモンを作成する必要がありました。 当時、私はGoを積極的に研究し、この言語が本当に好きだったので、賛否両論を検討した後、それにタスクを実装することにしました。 さらに、Goは既に安定しており、バージョン1.0.1でした。
私が直面しなければならなかった落とし穴について読んでください、カットの下で読んでください、しかし、私はすぐに予約をします:Goでの悪魔実装の微妙さだけを説明します。 「デーモン」とは何か、またはプロセスがどのように悪魔化されるのかわからない場合は、まずGoogleまたはLinuxデーモンハブで検索するか、記事の最後にあるリンクのリストを確認してください。
しかし、悪魔に戻って。 最初、私は古典的に行動することにしました:
- 子プロセスの生成と親の終了(フォークシステムコール);
- さらに子プロセスで:
- 新しく作成されたファイルのアクセス許可のマスクを設定する(umaskシステムコール);
- 新しいセッションを作成し、ターミナルから切断します(setsidシステムコール)。
- 作業ディレクトリをルートに変更します(システムコールchdir)。
- 標準I / Oストリーム記述子を/ dev / nullにリダイレクトします。
標準の
syscallパッケージにクリーンフォークが存在しなかったからといって私を止めることはできず、疑念を抱くことすらありませんでした。 私はこのようなことをしました(簡略化された):
ret, _, err := syscall.Syscall(syscall.SYS_FORK, 0, 0, 0) if err != 0 { os.Exit(2) } if ret > 0 {
すべてのポイントを実装し、デーモンを実行し、
ps -eafw
および
lsof -p , , .
, Go os/signal. , . fork, . . , code.google.com/p/go/issues/detail?id=227, . : Go fork, .. , , (goroutines), , , .
. , fork . os/signal, , :
func init() { signal_enable(0) // first call - initialize go loop() }
, , loop() . main(). loop() . , fork, loop(). , fork. init() fork, .
os/signal , init() Init() fork. .
- , : - - . , - , . , StartProcess . , , fork exec . , , , - . , . , _GO_DAEMON=1
.
:
const ( envVarName = "_GO_DAEMON" envVarValue = "1" ) func Reborn(umask uint32, workDir string) (err error) { if !WasReborn() { var path string if path, err = filepath.Abs(os.Args[0]); err != nil { return } cmd := exec.Command(path, os.Args[1:]...) envVar := fmt.Sprintf("%s=%s", envVarName, envVarValue) cmd.Env = append(os.Environ(), envVar) if err = cmd.Start(); err != nil { return } os.Exit(0) } syscall.Umask(int(umask)) if len(workDir) == 0 { if err = os.Chdir(workDir); err != nil { return } } _, err = syscall.Setsid() return } func WasReborn() bool { return os.Getenv(envVarName) == envVarValue }
. os/exec - StartProcess .
, , , , Reborn(), . - WasReborn(). (, ), Reborn(), Reborn() ( panic()), - /dev/null.
, , github: go-daemon . pid- . Go. - .
:
- Wikipedia
linux
golang.org
lsof -p , , .
, Go os/signal. , . fork, . . , code.google.com/p/go/issues/detail?id=227, . : Go fork, .. , , (goroutines), , , .
. , fork . os/signal, , :
func init() { signal_enable(0) // first call - initialize go loop() }
, , loop() . main(). loop() . , fork, loop(). , fork. init() fork, .
os/signal , init() Init() fork. .
- , : - - . , - , . , StartProcess . , , fork exec . , , , - . , . , _GO_DAEMON=1
.
:
const ( envVarName = "_GO_DAEMON" envVarValue = "1" ) func Reborn(umask uint32, workDir string) (err error) { if !WasReborn() { var path string if path, err = filepath.Abs(os.Args[0]); err != nil { return } cmd := exec.Command(path, os.Args[1:]...) envVar := fmt.Sprintf("%s=%s", envVarName, envVarValue) cmd.Env = append(os.Environ(), envVar) if err = cmd.Start(); err != nil { return } os.Exit(0) } syscall.Umask(int(umask)) if len(workDir) == 0 { if err = os.Chdir(workDir); err != nil { return } } _, err = syscall.Setsid() return } func WasReborn() bool { return os.Getenv(envVarName) == envVarValue }
. os/exec - StartProcess .
, , , , Reborn(), . - WasReborn(). (, ), Reborn(), Reborn() ( panic()), - /dev/null.
, , github: go-daemon . pid- . Go. - .
:
- Wikipedia
linux
golang.org
lsof -p , , .
, Go os/signal. , . fork, . . , code.google.com/p/go/issues/detail?id=227, . : Go fork, .. , , (goroutines), , , .
. , fork . os/signal, , :
func init() { signal_enable(0) // first call - initialize go loop() }
, , loop() . main(). loop() . , fork, loop(). , fork. init() fork, .
os/signal , init() Init() fork. .
- , : - - . , - , . , StartProcess . , , fork exec . , , , - . , . , _GO_DAEMON=1
.
:
const ( envVarName = "_GO_DAEMON" envVarValue = "1" ) func Reborn(umask uint32, workDir string) (err error) { if !WasReborn() { var path string if path, err = filepath.Abs(os.Args[0]); err != nil { return } cmd := exec.Command(path, os.Args[1:]...) envVar := fmt.Sprintf("%s=%s", envVarName, envVarValue) cmd.Env = append(os.Environ(), envVar) if err = cmd.Start(); err != nil { return } os.Exit(0) } syscall.Umask(int(umask)) if len(workDir) == 0 { if err = os.Chdir(workDir); err != nil { return } } _, err = syscall.Setsid() return } func WasReborn() bool { return os.Getenv(envVarName) == envVarValue }
. os/exec - StartProcess .
, , , , Reborn(), . - WasReborn(). (, ), Reborn(), Reborn() ( panic()), - /dev/null.
, , github: go-daemon . pid- . Go. - .
:
- Wikipedia
linux
golang.org
lsof -p , , .
, Go os/signal. , . fork, . . , code.google.com/p/go/issues/detail?id=227, . : Go fork, .. , , (goroutines), , , .
. , fork . os/signal, , :
func init() { signal_enable(0) // first call - initialize go loop() }
, , loop() . main(). loop() . , fork, loop(). , fork. init() fork, .
os/signal , init() Init() fork. .
- , : - - . , - , . , StartProcess . , , fork exec . , , , - . , . , _GO_DAEMON=1
.
:
const ( envVarName = "_GO_DAEMON" envVarValue = "1" ) func Reborn(umask uint32, workDir string) (err error) { if !WasReborn() { var path string if path, err = filepath.Abs(os.Args[0]); err != nil { return } cmd := exec.Command(path, os.Args[1:]...) envVar := fmt.Sprintf("%s=%s", envVarName, envVarValue) cmd.Env = append(os.Environ(), envVar) if err = cmd.Start(); err != nil { return } os.Exit(0) } syscall.Umask(int(umask)) if len(workDir) == 0 { if err = os.Chdir(workDir); err != nil { return } } _, err = syscall.Setsid() return } func WasReborn() bool { return os.Getenv(envVarName) == envVarValue }
. os/exec - StartProcess .
, , , , Reborn(), . - WasReborn(). (, ), Reborn(), Reborn() ( panic()), - /dev/null.
, , github: go-daemon . pid- . Go. - .
:
- Wikipedia
linux
golang.org
lsof -p , , .
, Go os/signal. , . fork, . . , code.google.com/p/go/issues/detail?id=227, . : Go fork, .. , , (goroutines), , , .
. , fork . os/signal, , :
func init() { signal_enable(0) // first call - initialize go loop() }
, , loop() . main(). loop() . , fork, loop(). , fork. init() fork, .
os/signal , init() Init() fork. .
- , : - - . , - , . , StartProcess . , , fork exec . , , , - . , . , _GO_DAEMON=1
.
:
const ( envVarName = "_GO_DAEMON" envVarValue = "1" ) func Reborn(umask uint32, workDir string) (err error) { if !WasReborn() { var path string if path, err = filepath.Abs(os.Args[0]); err != nil { return } cmd := exec.Command(path, os.Args[1:]...) envVar := fmt.Sprintf("%s=%s", envVarName, envVarValue) cmd.Env = append(os.Environ(), envVar) if err = cmd.Start(); err != nil { return } os.Exit(0) } syscall.Umask(int(umask)) if len(workDir) == 0 { if err = os.Chdir(workDir); err != nil { return } } _, err = syscall.Setsid() return } func WasReborn() bool { return os.Getenv(envVarName) == envVarValue }
. os/exec - StartProcess .
, , , , Reborn(), . - WasReborn(). (, ), Reborn(), Reborn() ( panic()), - /dev/null.
, , github: go-daemon . pid- . Go. - .
:
- Wikipedia
linux
golang.org