duanguochong0397 2016-05-06 22:36
浏览 280
已采纳

Golang exec程序并取消它

I am trying to fork processes with my daemon, and trying to disown them in case of my daemon crashes. Regular os/exec is high-level, therefore I went for syscall.ForkExec and produced the following code:

package main

import (
    "fmt"
    "os"
    "os/exec"
    "syscall"
    "time"
)

func main() {

    cmd := "myproc"
    binary, lookErr := exec.LookPath(cmd)
    if lookErr != nil {
        panic(lookErr)
    }
    fmt.Println(binary)

    os.Remove("/tmp/stdin")
    os.Remove("/tmp/stdout")
    os.Remove("/tmp/stderr")

    fstdin, err1 := os.Create("/tmp/stdin")
    fstdout, err2 := os.Create("/tmp/stdout")
    fstderr, err3 := os.Create("/tmp/stderr")
    if err1 != nil || err2 != nil || err3 != nil {
        fmt.Println(err1, err2, err3)
        panic("WOW")
    }

    argv := []string{"hi"}
    procAttr := syscall.ProcAttr{
        Dir:   "/tmp",
        Files: []uintptr{fstdin.Fd(), fstdout.Fd(), fstderr.Fd()},
        Env:   []string{"VAR1=ABC123"},
        Sys: &syscall.SysProcAttr{
            Foreground: false,
        },
    }

    pid, err := syscall.ForkExec(binary, argv, &procAttr)
    fmt.Println("Spawned proc", pid, err)

    time.Sleep(time.Second * 100)
}

I have also made a simple application that sleeps and prints hello world and put it to path.

#include <stdio.h>

int main(){
    while(1){
        printf("hello world");
        fflush(stdout);
        usleep(300000);
        }
}

It works, however, the process is not send to background as I expected, my go process still owns the child. The SysProcAttr has the following values in Linux:

type SysProcAttr struct {
    Chroot      string         // Chroot.
    Credential  *Credential    // Credential.
    Ptrace      bool           // Enable tracing.
    Setsid      bool           // Create session.
    Setpgid     bool           // Set process group ID to Pgid, or, if Pgid == 0, to new pid.
    Setctty     bool           // Set controlling terminal to fd Ctty (only meaningful if Setsid is set)
    Noctty      bool           // Detach fd 0 from controlling terminal
    Ctty        int            // Controlling TTY fd
    Foreground  bool           // Place child's process group in foreground. (Implies Setpgid. Uses Ctty as fd of controlling TTY)
    Pgid        int            // Child's process group ID if Setpgid.
    Pdeathsig   Signal         // Signal that the process will get when its parent dies (Linux only)
    Cloneflags  uintptr        // Flags for clone calls (Linux only)
    UidMappings []SysProcIDMap // User ID mappings for user namespaces.
    GidMappings []SysProcIDMap // Group ID mappings for user namespaces.
    // GidMappingsEnableSetgroups enabling setgroups syscall.
    // If false, then setgroups syscall will be disabled for the child process.
    // This parameter is no-op if GidMappings == nil. Otherwise for unprivileged
    // users this should be set to false for mappings work.
    GidMappingsEnableSetgroups bool
}

I also tried the following but It caused an error:

Sys: &syscall.SysProcAttr{
    Setsid:     true,
    Setctty:    true,
    Foreground: false,
 },

Spawned proc 0 inappropriate ioctl for device

Also the following:

Sys: &syscall.SysProcAttr{
    Setsid:     true,
    Setctty:    true,
    Foreground: false,
    Noctty:     true,
    Setpgid:    true,
},

Spawned proc 0 operation not permitted (with root privilleges)

What am I doing/assuming wrong? Note: Despite saying os/exec is high-level, I also tried the following, but it produced same results.

cs := exec.Command(binary)
cs.SysProcAttr = &syscall.SysProcAttr{
    Setctty: true,
}
err := cs.Run()
fmt.Println(err)
  • 写回答

4条回答 默认 最新

  • dongou4052 2017-10-15 13:24
    关注

    A process forked with Start() will continue even after its parent dies.

    func forker() {
        cmd := exec.Command("sleep", "3")
        cmd.Start()
        time.Sleep(2 * time.Second)
        os.Exit(1)
    }
    

    Here the sleep process will happily live on for 3 seconds even if the parent process only lives for 2 seconds:

      $ forker &; while true; do ps -f; sleep 1; done
    
      UID   PID  PPID   C STIME   TTY           TIME CMD
      501 71423 69892   0  3:01PM ttys003    0:00.07 forker
      501 71433 71432   0  3:01PM ttys003    0:00.00 sleep 3
    
      UID   PID  PPID   C STIME   TTY           TIME CMD
      501 71423 69892   0  3:01PM ttys003    0:00.07 forker
      501 71433 71432   0  3:01PM ttys003    0:00.00 sleep 3
    
      UID   PID  PPID   C STIME   TTY           TIME CMD
      501 71433     1   0  3:01PM ttys003    0:00.00 sleep 3
    

    Notice how the parent process ID (PPID) of the sleep process became 1 when the parent process 71432 exited. This means that the sleep process has been orphaned.

    本回答被题主选为最佳回答 , 对您是否有帮助呢?
    评论
查看更多回答(3条)

报告相同问题?

悬赏问题

  • ¥15 求差集那个函数有问题,有无佬可以解决
  • ¥15 【提问】基于Invest的水源涵养
  • ¥20 微信网友居然可以通过vx号找到我绑的手机号
  • ¥15 寻一个支付宝扫码远程授权登录的软件助手app
  • ¥15 解riccati方程组
  • ¥15 display:none;样式在嵌套结构中的已设置了display样式的元素上不起作用?
  • ¥15 使用rabbitMQ 消息队列作为url源进行多线程爬取时,总有几个url没有处理的问题。
  • ¥15 Ubuntu在安装序列比对软件STAR时出现报错如何解决
  • ¥50 树莓派安卓APK系统签名
  • ¥65 汇编语言除法溢出问题