Skip to content

Instantly share code, notes, and snippets.

@SCP002
Last active January 11, 2025 09:05
Show Gist options
  • Save SCP002/b0b8ceca7f6bf2f52ae04c93fede3904 to your computer and use it in GitHub Desktop.
Save SCP002/b0b8ceca7f6bf2f52ae04c93fede3904 to your computer and use it in GitHub Desktop.
Golang: Get all descendants of the specified process.
// Used in https://github.com/SCP002/terminator.
package main
import (
"errors"
"fmt"
"github.com/shirou/gopsutil/v4/process"
)
func main() {
fmt.Print("The PID to build a process tree from: ")
var pid int
_, _ = fmt.Scanln(&pid)
// Get a process tree.
tree := []*process.Process{}
err := FlatChildTree(pid, &tree, true)
if err != nil {
panic(err)
}
// Print collected info.
for _, proc := range tree {
cmdLine, err := proc.Cmdline()
if err != nil {
panic(err)
}
fmt.Printf("%v\t| %v\r\n", proc.Pid, cmdLine)
}
fmt.Println("Press <Enter> to exit...")
_, _ = fmt.Scanln()
}
// FlatChildTree populates the `tree` argument with gopsutil Process instances of all descendants of the process
// with PID `pid`.
//
// The first element in the tree is deepest descendant. The last one is a progenitor or closest child.
//
// If the `withRoot` argument is set to true, add the root process to the end.
func FlatChildTree(pid int, tree *[]*process.Process, withRoot bool) error {
proc, err := process.NewProcess(int32(pid))
if err != nil {
return err
}
children, err := proc.Children()
if errors.Is(err, process.ErrorNoChildren) {
return nil
}
if err != nil {
return err
}
// Iterate for each child process in reverse order.
for i := len(children) - 1; i >= 0; i-- {
child := children[i]
// Call self to collect descendants.
err := FlatChildTree(int(child.Pid), tree, false)
if err != nil {
return err
}
// Add the child after it's descendants.
*tree = append(*tree, child)
}
// Add the root process to the end.
if withRoot {
*tree = append(*tree, proc)
}
return nil
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment