Skip to content

Instantly share code, notes, and snippets.

@SCP002
Last active March 15, 2022 22:01
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 (
"fmt"
"github.com/shirou/gopsutil/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 := GetTree(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()
}
// GetTree populates the "tree" argument with gopsutil Process instances of all descendants of the specified process.
//
// 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", include the root process.
func GetTree(pid int, tree *[]process.Process, withRoot bool) error {
proc, err := process.NewProcess(int32(pid))
if err != nil {
return err
}
children, err := proc.Children()
if 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 := GetTree(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