79 lines
1.3 KiB
Go
79 lines
1.3 KiB
Go
// +build !windows
|
|
|
|
package kproc
|
|
|
|
import (
|
|
"context"
|
|
"os"
|
|
"os/exec"
|
|
"os/user"
|
|
"strconv"
|
|
"syscall"
|
|
|
|
"github.com/iwannay/log"
|
|
)
|
|
|
|
func CommandContext(ctx context.Context, name string, arg ...string) *KCmd {
|
|
cmd := exec.CommandContext(ctx, name, arg...)
|
|
cmd.SysProcAttr = &syscall.SysProcAttr{}
|
|
cmd.SysProcAttr.Setsid = true
|
|
return &KCmd{
|
|
ctx: ctx,
|
|
Cmd: cmd,
|
|
isKillChildProcess: true,
|
|
done: make(chan struct{}),
|
|
}
|
|
}
|
|
|
|
// SetUser 设置执行用户要保证root权限
|
|
func (k *KCmd) SetUser(username string) {
|
|
if username == "" {
|
|
return
|
|
}
|
|
u, err := user.Lookup(username)
|
|
if err != nil {
|
|
log.Error("setUser error:", err)
|
|
return
|
|
}
|
|
|
|
log.Infof("KCmd set uid=%s,gid=%s", u.Uid, u.Gid)
|
|
k.SysProcAttr = &syscall.SysProcAttr{}
|
|
uid, _ := strconv.Atoi(u.Uid)
|
|
gid, _ := strconv.Atoi(u.Gid)
|
|
k.SysProcAttr.Credential = &syscall.Credential{Uid: uint32(uid), Gid: uint32(gid)}
|
|
|
|
}
|
|
|
|
func (k *KCmd) KillAll() {
|
|
|
|
select {
|
|
case k.done <- struct{}{}:
|
|
default:
|
|
}
|
|
|
|
if k.Process == nil {
|
|
return
|
|
}
|
|
|
|
if k.isKillChildProcess == false {
|
|
return
|
|
}
|
|
|
|
group, err := os.FindProcess(-k.Process.Pid)
|
|
if err == nil {
|
|
group.Signal(syscall.SIGKILL)
|
|
}
|
|
}
|
|
|
|
func (k *KCmd) Wait() error {
|
|
defer k.KillAll()
|
|
go func() {
|
|
select {
|
|
case <-k.ctx.Done():
|
|
k.KillAll()
|
|
case <-k.done:
|
|
}
|
|
}()
|
|
return k.Cmd.Wait()
|
|
}
|