Warning: file_get_contents(/data/phpspider/zhask/data//catemap/3/go/7.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Linux Golang exec流程和否认它_Linux_Go_Fork_Exec - Fatal编程技术网

Linux Golang exec流程和否认它

Linux Golang exec流程和否认它,linux,go,fork,exec,Linux,Go,Fork,Exec,我试图用我的守护进程来分叉进程,并试图在守护进程崩溃的情况下与它们断开连接。常规的os/exec是高级的,因此我选择了syscall.ForkExec并生成了以下代码: package main import ( "fmt" "os" "os/exec" "syscall" "time" ) func main() { cmd := "myproc" binary, lookErr := exec.LookPath(cmd)

我试图用我的守护进程来分叉进程,并试图在守护进程崩溃的情况下与它们断开连接。常规的
os/exec
是高级的,因此我选择了
syscall.ForkExec
并生成了以下代码:

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)
}
我还制作了一个简单的应用程序,用于睡眠和打印hello world,并将其置于path

#include <stdio.h>

int main(){
    while(1){
        printf("hello world");
        fflush(stdout);
        usleep(300000);
        }
}
我还尝试了以下操作,但出现了错误:

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

Spawned proc 0 inappropriate ioctl for device
还包括:

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

Spawned proc 0 operation not permitted (with root privilleges)
我做错了什么? 注意:尽管我说os/exec是高级的,但我也尝试了以下方法,但得到了相同的结果

cs := exec.Command(binary)
cs.SysProcAttr = &syscall.SysProcAttr{
    Setctty: true,
}
err := cs.Run()
fmt.Println(err)
你应该得到你想要的东西。示例Go程序终止后附加简单文本文件的脚本继续运行:

package main

import (
    "os/exec"
)

func main() {
    cmd := exec.Command("./appender.sh")
    cmd.Start()
}

Start()
分叉的进程即使在其父进程死亡后也将继续

func forker() {
    cmd := exec.Command("sleep", "3")
    cmd.Start()
    time.Sleep(2 * time.Second)
    os.Exit(1)
}
在这里,
睡眠
进程将愉快地持续3秒,即使父进程只持续2秒:

  $ 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

请注意当父进程退出时,
sleep
进程的父进程ID(
PPID
)如何变成
1
。这意味着
sleep
进程已被孤立。

立即断开连接的好策略是生成
os.Argv[0]
进程(自生成),然后生成目标进程(setId:true),然后退出第一个生成的进程。这样,gradchild进程立即获得PPID1。可选地,第一个生成的进程可以在退出之前通过标准输出将granchild的pid传递给父进程。

守护进程化与go的goroutine调度不匹配,因此细节变得非常复杂。有一个小的实现,有好的讨论和链接到更多好的讨论,还有更流行和更传统的实现

几乎可以肯定,您所遇到的
ioctl
错误来自于使用


Sys:&syscall.SysProcAttr{
前景:错,
塞西德:是的,
},

应该得到类似于
os/exec
Start
的语义,其中子进程不会立即重新租用,但在父进程死亡时会安全地被提升

func forker() {
    cmd := exec.Command("sleep", "3")
    cmd.Start()
    time.Sleep(2 * time.Second)
    os.Exit(1)
}
您看到的
操作是不允许的
,我想是关于
/tmp/
中的管道在strace下运行:

openat(AT_FDCWD,“/tmp/stdin”,O_RDWR | O|u CREAT | O|u TRUNC | O|u CLOEXEC,0666)=3
epoll_create1(epoll_CLOEXEC)=4
epoll_ctl(4,epoll_ctl_ADD,3,{EPOLLIN|EPOLLOUT | epolldhup | EPOLLET,{u32=471047936,u64=140179613654784}})=-1 EPERM(不允许操作)
epoll_ctl(4,epoll_ctl_DEL,3,0xc420039c24)=-1 EPERM(不允许操作)
openat(AT_FDCWD,“/tmp/stdout”,O_RDWR | O|u CREAT | O|u TRUNC | O|u CLOEXEC,0666)=5
epoll_ctl(4,epoll_ctl_ADD,5,{EPOLLIN|EPOLLOUT | epolldhup | EPOLLET,{u32=471047936,u64=140179613654784}})=-1 EPERM(不允许操作)
epoll_ctl(4,epoll_ctl_DEL,5,0xc420039c24)=-1 EPERM(不允许操作)
openat(AT_FDCWD,“/tmp/stderr”,O_RDWR | O|u CREAT | O|u TRUNC | O|u CLOEXEC,0666)=6
epoll_ctl(4,epoll_ctl_ADD,6,{EPOLLIN|EPOLLOUT | epolldhup | EPOLLET,{u32=471047936,u64=140179613654784}})=-1 EPERM(不允许操作)
epoll_ctl(4,epoll_ctl_DEL,6,0xc420039c24)=-1 EPERM(不允许操作)

为什么您认为
exec.Cmd
的级别太高?您也可以从那里访问sysprocatr。另外,您的流程仍然拥有孩子是什么意思?是否在同一流程组中?如果父进程退出,它不会被重新分配到PID 1吗?请注意,如果命令使用来自父进程的stdin/stdout,如果父进程终止,进程可能会变成僵尸。@Anferne我正在执行一个Go程序的bash脚本,该程序在一个阶段内终止父进程Go。我在cmd.Start()之前提供了“stderr,\:=cmd.StderrPipe()”,并注意到运行脚本的子进程也会在父进程go进程被终止后死亡。一旦我删除了stderr行并执行了该程序,子进程就会正确地继续执行。如果我不明白你的意思,请原谅,但这就是你在上述评论中提到的吗?在上面的例子中,目标是使71432等于1(立即)。问题的措辞是:“[…]以防我的守护进程崩溃[sic]”。没有必要立即取消该过程。使用
Start()。