在Go中启动一个进程并从中分离

Kha*_*ash 7 linux process go

我需要在Go中启动一个具有以下要求的新进程:

  • 即使在Go过程终止后,启动过程也应该运行
  • 我需要能够设置正在运行它的Unix用户/组
  • 我需要能够设置继承的环境变量
  • 我需要控制std in/out/err

这是一个尝试:

var attr = os.ProcAttr {
Dir: "/bin",
Env: os.Environ(),
Files: []*os.File{
    os.Stdin,
    "stdout.log",
    "stderr.log",
  },
}
process, err := os.StartProcess("sleep", []string{"1"}, &attr)
Run Code Online (Sandbox Code Playgroud)

这工作正常,但有以下缺点:

  • 无法设置Unix用户/组
  • 当Go进程(父进程)停止时,已启动的进程结束

只有在简化了事情的情况下,才需要在Linux上运行.

小智 11

  1. 您可以使用process.Release将子进程与父进程分离,并使其在父进程死亡后继续存在
  2. 查看*os.ProcAttr.Sys.Credentials属性的定义:它看起来像使用您可以设置进程用户和组ID的属性.

这是您的示例的工作版本(我没有检查进程ID是否实际上是一个集合)

package main

import "fmt"
import "os"
import "syscall"

const (
    UID = 501
    GUID = 100
    )


func main() {
    // The Credential fields are used to set UID, GID and attitional GIDS of the process
    // You need to run the program as  root to do this
        var cred =  &syscall.Credential{ UID, GUID, []uint32{} }
    // the Noctty flag is used to detach the process from parent tty
    var sysproc = &syscall.SysProcAttr{  Credential:cred, Noctty:true }
    var attr = os.ProcAttr{
        Dir: ".",
        Env: os.Environ(),
        Files: []*os.File{
            os.Stdin,
            nil,
            nil,
        },
            Sys:sysproc,

    }
    process, err := os.StartProcess("/bin/sleep", []string{"/bin/sleep", "100"}, &attr)
    if err == nil {

        // It is not clear from docs, but Realease actually detaches the process
        err = process.Release();
        if err != nil {
            fmt.Println(err.Error())
        }

    } else {
        fmt.Println(err.Error())
    }
}
Run Code Online (Sandbox Code Playgroud)