/
githubmirror
/
client
Обзор
Документация
Войти
/
githubmirror
/
client
Код
Запросы
0
Пакеты
0
Релизы
0
Аналитика
Безопасность
master
go/updater/process/process.go
219 строк
7 KB
chrisnojima-zoom
Version 670 - clean2 (#29122)
08 июн 2026, 19:31
Не верифицирован
08 июн 2026, 19:31
1943197
Код
Авторство
О чём код?
// Copyright 2015 Keybase, Inc. All rights reserved. Use of // this source code is governed by the included BSD license. package process import ( "fmt" "os" "runtime" "syscall" "time" "github.com/keybase/go-ps" ) // Log is the logging interface for the process package type Log interface { Debugf(s string, args ...any) Infof(s string, args ...any) Warningf(s string, args ...any) Errorf(s string, args ...any) } type ( processesFn func() ([]ps.Process, error) breakFn func([]ps.Process) bool ) // FindProcesses returns processes containing string matching process path func FindProcesses(matcher Matcher, wait time.Duration, delay time.Duration, log Log) ([]ps.Process, error) { breakFn := func(procs []ps.Process) bool { return len(procs) > 0 } return findProcesses(matcher, breakFn, wait, delay, log) } // WaitForExit returns processes (if any) that are still running after wait func WaitForExit(matcher Matcher, wait time.Duration, delay time.Duration, log Log) ([]ps.Process, error) { breakFn := func(procs []ps.Process) bool { return len(procs) == 0 } return findProcesses(matcher, breakFn, wait, delay, log) } func findProcesses(matcher Matcher, breakFn breakFn, wait time.Duration, delay time.Duration, log Log) ([]ps.Process, error) { start := time.Now() for { log.Debugf("Find process %s (%s < %s)", matcher.match, time.Since(start), wait) procs, err := findProcessesWithFn(ps.Processes, matcher.Fn(), 0) if err != nil { return nil, err } if breakFn(procs) { return procs, nil } if time.Since(start) >= wait { break } time.Sleep(delay) } return nil, nil } // findProcessWithPID returns a process for a pid. // Consider using os.FindProcess instead if suitable since this may be // inefficient. func findProcessWithPID(pid int) (ps.Process, error) { matchPID := func(p ps.Process) bool { return p.Pid() == pid } procs, err := findProcessesWithFn(ps.Processes, matchPID, 1) if err != nil { return nil, err } if len(procs) == 0 { return nil, nil } return procs[0], nil } // Currently findProcessWithPID is only used in tests, ignore deadcode warning var _ = findProcessWithPID // findProcessesWithFn finds processes using match function. // If max is != 0, then we will return that max number of processes. func findProcessesWithFn(fn processesFn, matchFn MatchFn, maxV int) ([]ps.Process, error) { processes, err := fn() if err != nil { return nil, fmt.Errorf("Error listing processes: %s", err) } if processes == nil { return nil, nil } procs := []ps.Process{} for _, p := range processes { if matchFn(p) { procs = append(procs, p) } if maxV != 0 && len(procs) >= maxV { break } } return procs, nil } // FindPIDsWithMatchFn returns pids for processes matching function func FindPIDsWithMatchFn(matchFn MatchFn, log Log) ([]int, error) { return findPIDsWithFn(ps.Processes, matchFn, log) } func findPIDsWithFn(fn processesFn, matchFn MatchFn, log Log) ([]int, error) { procs, err := findProcessesWithFn(fn, matchFn, 0) if err != nil { log.Errorf("Error finding matching processes") return nil, err } pids := []int{} for _, p := range procs { pids = append(pids, p.Pid()) } log.Debugf("Found %d matching processes with pids: %s", len(procs), pids) return pids, nil } // TerminateAll stops all processes with executable names that contains the matching string. // It returns the pids that were terminated. // This method only logs errors, if you need error handling, you can should use a different implementation. func TerminateAll(matcher Matcher, killDelay time.Duration, log Log) []int { return TerminateAllWithProcessesFn(ps.Processes, matcher.Fn(), killDelay, log) } // TerminateAllWithProcessesFn stops processes processesFn that satify the matchFn. // It returns the pids that were terminated. // This method only logs errors, if you need error handling, you can should use a different implementation. func TerminateAllWithProcessesFn(fn processesFn, matchFn MatchFn, killDelay time.Duration, log Log) (terminatedPids []int) { pids, err := findPIDsWithFn(fn, matchFn, log) if err != nil { log.Errorf("Error finding process: %s", err) return terminatedPids } if len(pids) == 0 { return terminatedPids } for _, pid := range pids { if err := TerminatePID(pid, killDelay, log); err != nil { log.Errorf("Error terminating %d: %s", pid, err) continue } log.Debugf("Successfully terminated %s", pid) terminatedPids = append(terminatedPids, pid) } return terminatedPids } // TerminatePID is an overly simple way to terminate a PID. // On darwin and linux, it calls SIGTERM, then waits a killDelay and then calls // SIGKILL. We don't mind if we call SIGKILL on an already terminated process, // since there could be a race anyway where the process exits right after we // check if it's still running but before the SIGKILL. // The killDelay is not used on windows. func TerminatePID(pid int, killDelay time.Duration, log Log) error { log.Debugf("Searching OS for %d to terminate", pid) process, err := os.FindProcess(pid) if err != nil { return fmt.Errorf("Error finding OS process: %s", err) } if process == nil { return fmt.Errorf("No process found with pid %d", pid) } // Sending SIGTERM is not supported on windows, so we can use process.Kill() if runtime.GOOS == "windows" { return process.Kill() } log.Debugf("Terminating: %#v", process) err = process.Signal(syscall.SIGTERM) if err != nil { log.Warningf("Error sending terminate: %s", err) } log.Debugf("Waiting %s", killDelay) time.Sleep(killDelay) log.Debugf("Done waiting") // Ignore SIGKILL error since it will be that the process wasn't running if // the terminate above succeeded. If terminate didn't succeed above, then // this SIGKILL is a measure of last resort, and an error would signify that // something in the environment has gone terribly wrong. _ = process.Kill() return err } // KillAll kills all processes that match func KillAll(matcher Matcher, log Log) (pids []int) { pids, err := findPIDsWithFn(ps.Processes, matcher.Fn(), log) if err != nil { log.Errorf("Error finding process: %s", err) return } if len(pids) == 0 { return } for _, pid := range pids { if err := KillPID(pid, log); err != nil { log.Errorf("Error killing %d: %s", pid, err) } } return } // KillPID kills process at pid (sends a SIGKILL on unix) func KillPID(pid int, log Log) error { log.Debugf("Searching OS for %d to kill", pid) process, err := os.FindProcess(pid) if err != nil { return fmt.Errorf("Error finding OS process: %s", err) } if process == nil { return fmt.Errorf("No process found with pid %d", pid) } return process.Kill() }