func()

in pcap-cli/pkg/pcap/tcpdump_engine.go [96:163]


func (t *Tcpdump) Start(
	ctx context.Context,
	_ []PcapWriter,
	stopDeadline <-chan *time.Duration,
) error {
	// atomically activate the packet capture
	if !t.isActive.CompareAndSwap(false, true) {
		return fmt.Errorf("already started")
	}

	args := t.buildArgs(ctx)

	cmd := exec.CommandContext(ctx, t.tcpdump, args...)

	// prevent child process from hijacking signals
	cmd.SysProcAttr = &syscall.SysProcAttr{
		Setpgid: true, Pgid: 0,
	}

	cmd.Stdout = os.Stdout
	cmd.Stderr = os.Stderr
	cmd.WaitDelay = 1900 * time.Millisecond

	cmdLine := strings.Join(cmd.Args[:], " ")
	if err := cmd.Start(); err != nil {
		tcpdumpLogger.Printf("'%+v' - error: %+v\n", cmdLine, err)
		return err
	}

	pid := cmd.Process.Pid
	tcpdumpLogger.Printf("EXEC(%d): %v\n", pid, cmdLine)

	<-ctx.Done()
	ctxDoneTS := time.Now()

	if err := cmd.Process.Signal(syscall.SIGTERM); err != nil {
		tcpdumpLogger.Printf("[pid:%d] - %+v' - error: %+v\n", pid, cmdLine, err)
		cmd.Process.Kill()
	}

	cmdStopChan := make(chan error, 1)
	go func(cmd *exec.Cmd, cmdStopChan chan<- error) {
		cmdStopChan <- cmd.Wait()
	}(cmd, cmdStopChan)

	engineStopDeadline := <-stopDeadline
	engineStopTimeout := *engineStopDeadline - time.Since(ctxDoneTS)
	timer := time.NewTimer(engineStopTimeout)

	var err error
	select {
	case <-timer.C:
		err = context.DeadlineExceeded
	case err = <-cmdStopChan:
		if !timer.Stop() {
			<-timer.C
		}
		close(cmdStopChan)
	}

	// make sure previous execution does not survive
	killedProcs, numProcs, killErr := t.findAndKill(pid)
	tcpdumpLogger.Printf("STOP [tcpdump(%d)] <%d/%d>: %+v\n", pid, killedProcs, numProcs, cmdLine)

	t.isActive.Store(false)

	return errors.Join(ctx.Err(), err, killErr)
}