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)
}