为了账号安全,请及时绑定邮箱和手机立即绑定

Golang exec 进程并否认它

Golang exec 进程并否认它

Go
叮当猫咪 2022-01-10 14:22:08
我正在尝试使用我的守护进程来分叉进程,并试图在我的守护进程崩溃时不承认它们。常规os/exec是高级别的,因此我选择syscall.ForkExec并生成了以下代码:package mainimport (    "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 并将其放入路径。#include <stdio.h>int main(){    while(1){        printf("hello world");        fflush(stdout);        usleep(300000);        }}它可以工作,但是,该过程没有像我预期的那样发送到后台,我的 go 过程仍然拥有孩子。该SysProcAttr拥有的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}
查看完整描述

3 回答

?
aluckdog

TA贡献1847条经验 获得超7个赞

Start()即使在其父进程死亡后,被分叉的进程仍将继续。


func forker() {

    cmd := exec.Command("sleep", "3")

    cmd.Start()

    time.Sleep(2 * time.Second)

    os.Exit(1)

}

在这里,sleep即使父进程只存活 2 秒,该进程也会愉快地存活 3 秒:


  $ 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

通知父进程ID(如何PPID)的的sleep过程变得1当父进程71432退出。这意味着该sleep进程已被孤立。


查看完整回答
反对 回复 2022-01-10
?
HUX布斯

TA贡献1876条经验 获得超6个赞

似乎立即放弃的好策略是os.Argv[0]生成进程(自生成),然后生成目标进程(使用 Setsid:true),然后退出第一个生成的进程。这样 gradchild 进程立即获得 ppid 1。可选地,第一个衍生的进程可以在退出之前通过 stdout 将孙子的 pid 传递给父进程。


查看完整回答
反对 回复 2022-01-10
?
冉冉说

TA贡献1877条经验 获得超1个赞

在Start()方法应该给你你在找什么。我的示例 Go 程序终止后附加一个简单文本文件的脚本继续运行:


package main


import (

    "os/exec"

)


func main() {

    cmd := exec.Command("./appender.sh")

    cmd.Start()

}


查看完整回答
反对 回复 2022-01-10
  • 3 回答
  • 0 关注
  • 153 浏览
慕课专栏
更多

添加回答

举报

0/150
提交
取消
意见反馈 帮助中心 APP下载
官方微信