Files
reniced/main.go
2024-03-12 23:14:55 +03:00

182 lines
4.8 KiB
Go

package main
import (
"log"
"os"
"strings"
"syscall"
"time"
proc "github.com/shirou/gopsutil/v3/process"
)
// main основная функция программы.
func main() {
if os.Getenv("HOME") == "" {
log.Fatalln("Unable to get HOME environment variable value")
}
cnf, err := readConf(os.Getenv("HOME") + "/.reniced.yaml")
if err != nil {
log.Fatalf("unable to parse config: %s", err)
}
// Основной цикл.
for {
processList, err := proc.Processes()
if err != nil {
log.Fatalf("Unable to get process list: %s", err)
}
// Не самый эффективный, зато работающий способ - простой перебор массивов.
for _, p := range processList {
if processName, err := p.Name(); err == nil {
for _, k := range cnf.Kill {
for _, killProcessName := range k.Name {
if processName == killProcessName {
switch k.Sig {
case "kill":
_ = p.SendSignal(syscall.SIGKILL)
if cnf.Debug {
log.Printf(
"Matching processName with killProcessname (%s), SIG%s sent",
processName,
strings.ToUpper(k.Sig),
)
}
case "stop":
if s, err := p.Status(); err == nil && s[0] != "stop" {
_ = p.SendSignal(syscall.SIGSTOP)
if cnf.Debug {
log.Printf(
"Matching processName with killProcessname (%s), SIG%s sent",
processName,
strings.ToUpper(k.Sig),
)
}
} else if err == nil && s[0] == "stop" && cnf.Debug {
log.Printf(
"Matching processName with killProcessname (%s) and it is already stopped",
processName,
)
}
case "term":
_ = p.SendSignal(syscall.SIGTERM)
if cnf.Debug {
log.Printf(
"Matching processName with killProcessname (%s), SIG%s sent",
processName,
strings.ToUpper(k.Sig),
)
}
case "int":
_ = p.SendSignal(syscall.SIGINT)
if cnf.Debug {
log.Printf(
"Matching processName with killProcessname (%s), SIG%s sent",
processName,
strings.ToUpper(k.Sig),
)
}
case "quit":
_ = p.SendSignal(syscall.SIGQUIT)
if cnf.Debug {
log.Printf(
"Matching processName with killProcessname (%s), SIG%s sent",
processName,
strings.ToUpper(k.Sig),
)
}
case "abrt":
_ = p.SendSignal(syscall.SIGABRT)
if cnf.Debug {
log.Printf(
"Matching processName with killProcessname (%s), SIG%s sent",
processName,
strings.ToUpper(k.Sig),
)
}
case "hup":
_ = p.SendSignal(syscall.SIGHUP)
if cnf.Debug {
log.Printf(
"Matching processName with killProcessname (%s), SIG%s sent",
processName,
strings.ToUpper(k.Sig),
)
}
case "usr1":
_ = p.SendSignal(syscall.SIGUSR1)
if cnf.Debug {
log.Printf(
"Matching processName with killProcessname (%s), SIG%s sent",
processName,
strings.ToUpper(k.Sig),
)
}
case "usr2":
_ = p.SendSignal(syscall.SIGUSR2)
if cnf.Debug {
log.Printf(
"Matching processName with killProcessname (%s), SIG%s sent",
processName,
strings.ToUpper(k.Sig),
)
}
}
}
}
}
// Для каждого процесса извлекаем его текущий nicelevel.
if currentNiceLevel, err := p.Nice(); err == nil {
// Вынимаем список приоритетов.
for _, n := range cnf.Prio {
// Для каждого приоритета, проходимся по списку имён процессов.
for _, name := range n.Name {
// Достаём имя текущего процесса.
if processName, err = p.Name(); err == nil {
// Если имя процесса совпадает с одним из списка в конфиге, то пробуем менять ему nice.
if processName == name {
if currentNiceLevel != n.Nice {
_ = syscall.Setpriority(syscall.PRIO_PROCESS, int(p.Pid), int(n.Nice))
if cnf.Debug {
log.Printf(
"Set niceness for %s(%d) to %d (was %d)",
name,
p.Pid,
n.Nice,
currentNiceLevel,
)
}
} else if cnf.Debug {
log.Printf("Nicelevel for %d already set to %d", p.Pid, n.Nice)
}
}
}
}
}
}
}
time.Sleep(time.Millisecond * time.Duration(cnf.CmdDelay))
}
time.Sleep(time.Millisecond * time.Duration(cnf.LoopDelay))
}
}
/* vim: set ft=go noet ai ts=4 sw=4 sts=4: */