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

时间:2014-04-12 14:35:04

标签: 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)

这样可以正常工作,但要求有以下缺点:

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

只有在简化了事情时才需要在Linux上运行。

2 个答案:

答案 0 :(得分:9)

  1. 您可以使用process.Release将子进程与父进程分离,并使其在父级死亡后继续存在
  2. 查看* os.ProcAttr.Sys.Credentials属性的定义:它看起来像使用您可以设置进程用户和组ID的属性。
  3. 以下是您的示例的工作版本(我没有检查进程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())
        }
    }
    

答案 1 :(得分:2)

我发现似乎跨平台工作的是使用特殊标志重新运行程序。在主程序中,检查此标志。如果在启动时出现,您就可以进入" fork"。如果不存在,请使用标志重新运行该命令。

<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<select id='yearGroup'></select><br>

<label for="Maths" id="labelMaths">Maths</label><input type="radio" name="subjects" value="Maths" id="Maths">
<label for="English" id="labelEnglish">English</label><input type="radio" name="subjects" value="English" id="English">
<label for="French" id="labelFrench">French</label><input type="radio" name="subjects" value="French" id="French">
<label for="History" id="labelHistory">History</label><input type="radio" name="subjects" value="History" id="History">
<label for="Geography" id="labelGeography">Geography</label><input type="radio" name="subjects" value="Geography" id="Geography">

这将只使用确切的参数重新运行您的过程并将func rerunDetached() error { cwd, err := os.Getwd() if err != nil { return err } args := append(os.Args, "--detached") cmd := exec.Command(args[0], args[1:]...) cmd.Dir = cwd err = cmd.Start() if err != nil { return err } cmd.Process.Release() return nil } 附加到参数。程序启动时,请检查--detached标志,以了解是否需要致电--detached。这有点像一个可怜的勒芒rerunDetached,可以在不同的操作系统上工作。