88 lines
1.7 KiB
Go
88 lines
1.7 KiB
Go
package pidof
|
|
|
|
import (
|
|
"errors"
|
|
"fmt"
|
|
"os/exec"
|
|
"regexp"
|
|
"strconv"
|
|
"strings"
|
|
"syscall"
|
|
|
|
log "github.com/sirupsen/logrus"
|
|
)
|
|
|
|
//go:generate mockery --name Commander --inpackage --output .
|
|
|
|
var ErrPIDNotFound = fmt.Errorf("could not find pid")
|
|
|
|
type Commander interface {
|
|
Output(cmd string) ([]byte, error)
|
|
}
|
|
|
|
type Cdr struct{}
|
|
|
|
func (c Cdr) Output(cmd string) ([]byte, error) {
|
|
cm := exec.Command("/bin/sh", "-c", cmd)
|
|
|
|
log.WithField("cmd", cm.String()).Debug("command to run")
|
|
|
|
// nolint:wrapcheck
|
|
return cm.Output()
|
|
}
|
|
|
|
func Pidof(name string, cdr Commander) (int, error) {
|
|
p, err := cdr.Output(fmt.Sprintf("ps a|grep '%s'", name))
|
|
if err != nil {
|
|
log.WithField("output", p).Debug(p)
|
|
|
|
return 0, fmt.Errorf("could not execute ps command: %w", err)
|
|
}
|
|
|
|
for _, l := range strings.Split(string(p), "\n") {
|
|
if strings.Contains(l, name) && !strings.Contains(l, "grep") {
|
|
// nolint:gocritic
|
|
rePID, err := regexp.Compile(`(\d+)\s.+`)
|
|
if err != nil {
|
|
return 0, fmt.Errorf("could not compile re: %w", err)
|
|
}
|
|
|
|
matches := rePID.FindStringSubmatch(l)
|
|
// nolint: gomnd
|
|
if len(matches) == 2 {
|
|
pid, err := strconv.Atoi(matches[1])
|
|
if err != nil {
|
|
return 0, fmt.Errorf("could not convert string to int: %w", err)
|
|
}
|
|
|
|
return pid, nil
|
|
}
|
|
|
|
break
|
|
}
|
|
}
|
|
|
|
return 0, ErrPIDNotFound
|
|
}
|
|
|
|
func Pkill(name string) error {
|
|
c := Cdr{}
|
|
|
|
pid, err := Pidof(name, c)
|
|
if err != nil {
|
|
if errors.Is(err, ErrPIDNotFound) {
|
|
log.Debug("looks like the process is not running")
|
|
|
|
return nil
|
|
}
|
|
|
|
return fmt.Errorf("could not get pid: %w", err)
|
|
}
|
|
|
|
if err := syscall.Kill(pid, 9); err != nil {
|
|
return fmt.Errorf("could not kill process: %w", err)
|
|
}
|
|
|
|
return nil
|
|
}
|