107 lines
2.4 KiB
Go
107 lines
2.4 KiB
Go
package main
|
|
|
|
import (
|
|
"flag"
|
|
"fmt"
|
|
"jsh"
|
|
"math"
|
|
"os"
|
|
"os/exec"
|
|
"strings"
|
|
"unicode"
|
|
)
|
|
|
|
// FieldsN slices s into substrings after each instance of a whitespace
|
|
// character (according to unicode.IsSpace) and returns a slice of those
|
|
// substrings. The slice's length is guaranteed to be at most maxN, and
|
|
// all leftover fields are put into the last substring.
|
|
func FieldsN(s string, maxN int) []string {
|
|
// First count the fields.
|
|
n := 0
|
|
inField := false
|
|
for _, rune := range s {
|
|
wasInField := inField
|
|
inField = !unicode.IsSpace(rune)
|
|
if inField && !wasInField {
|
|
n++
|
|
}
|
|
}
|
|
n = int(math.Min(float64(n), float64(maxN)))
|
|
|
|
// Now create them.
|
|
a := make([]string, n)
|
|
na := 0
|
|
fieldStart := -1 // Set to -1 when looking for start of field.
|
|
for i, rune := range s {
|
|
if unicode.IsSpace(rune) && na+1 < maxN {
|
|
if fieldStart >= 0 {
|
|
a[na] = s[fieldStart:i]
|
|
na++
|
|
fieldStart = -1
|
|
}
|
|
} else if fieldStart == -1 {
|
|
fieldStart = i
|
|
}
|
|
}
|
|
if fieldStart >= 0 { // Last field might end at EOF.
|
|
a[na] = s[fieldStart:]
|
|
}
|
|
return a
|
|
}
|
|
|
|
// Falls back to procps-ng passing the space-separated arguments in the given
|
|
// args slice. If args is nil, we default to the arguments passed to the command
|
|
// line using os.Args
|
|
func fallbackCompletelyWithArgs(args []string) *[]byte {
|
|
if args == nil {
|
|
args = os.Args[1:]
|
|
}
|
|
out, err := exec.Command("/usr/bin/ps", args...).Output()
|
|
if err != nil {
|
|
panic(err)
|
|
}
|
|
return &out
|
|
}
|
|
|
|
// Falls back to procps-ng with no default arguments
|
|
func fallbackCompletely() *[]byte {
|
|
return fallbackCompletelyWithArgs(nil)
|
|
}
|
|
|
|
// Converts raw output of "ps" into a slice of Process objects
|
|
func psOutputToProcesses(out string) *[]jsh.Process {
|
|
processes := []jsh.Process{}
|
|
lines := strings.Split(out, "\n")
|
|
header, procs := lines[0], lines[1:]
|
|
numFields := len(strings.Fields(header))
|
|
|
|
for _, proc := range procs {
|
|
p, err := jsh.NewProcess(FieldsN(proc, numFields))
|
|
if err == nil {
|
|
processes = append(processes, *p)
|
|
}
|
|
}
|
|
return &processes
|
|
}
|
|
|
|
func runJsonMode() {
|
|
// Run procps-ng "ps" with full output
|
|
psOut := string(*fallbackCompletelyWithArgs([]string{"auxww"}))
|
|
|
|
processesPtr := psOutputToProcesses(psOut)
|
|
finalOut := jsh.JshOutput{*processesPtr, []string{}}
|
|
fmt.Printf("%s", *finalOut.ToJson())
|
|
}
|
|
|
|
func main() {
|
|
// Parse for JSON flag.
|
|
jsonModePtr := flag.Bool("json", false, "a bool")
|
|
flag.Parse()
|
|
|
|
if !*jsonModePtr {
|
|
fmt.Printf("%s", fallbackCompletely())
|
|
} else {
|
|
runJsonMode()
|
|
}
|
|
}
|