fortify: clean up ps formatting code
All checks were successful
Tests / Go tests (push) Successful in 38s
Nix / NixOS tests (push) Successful in 3m1s

Signed-off-by: Ophestra <cat@gensokyo.uk>
This commit is contained in:
Ophestra 2024-12-21 20:34:40 +09:00
parent 4f4c690d38
commit cb98baa19d
Signed by: cat
SSH Key Fingerprint: SHA256:gQ67O0enBZ7UdZypgtspB2FDM1g3GVw8nX0XSdcFw8Q
4 changed files with 85 additions and 127 deletions

View File

@ -21,6 +21,11 @@ _fortify_run() {
'--dbus-log[Force logging in the D-Bus proxy]' '--dbus-log[Force logging in the D-Bus proxy]'
} }
_fortify_ps() {
_arguments \
'--short[Print instance id]'
}
(( $+functions[_fortify_commands] )) || _fortify_commands() (( $+functions[_fortify_commands] )) || _fortify_commands()
{ {
local -a _fortify_cmds local -a _fortify_cmds

View File

@ -1,118 +0,0 @@
package state
import (
"fmt"
"os"
"strings"
"text/tabwriter"
"time"
"git.gensokyo.uk/security/fortify/internal/fmsg"
"git.gensokyo.uk/security/fortify/internal/system"
)
// MustPrintLauncherStateSimpleGlobal prints active launcher states of all simple stores
// in an implementation-specific way.
func MustPrintLauncherStateSimpleGlobal(w **tabwriter.Writer, runDir string) {
now := time.Now().UTC()
s := NewMulti(runDir)
// read runtime directory to get all UIDs
if aids, err := s.List(); err != nil {
fmsg.Fatal("cannot list store:", err)
} else {
for _, aid := range aids {
// print states belonging to this store
s.(*multiStore).mustPrintLauncherState(aid, w, now)
}
}
// mustPrintLauncherState causes store activity so store needs to be closed
if err := s.Close(); err != nil {
fmsg.Printf("cannot close store: %v", err)
}
}
func (s *multiStore) mustPrintLauncherState(aid int, w **tabwriter.Writer, now time.Time) {
var innerErr error
if ok, err := s.Do(aid, func(c Cursor) {
innerErr = func() error {
// read launcher states
states, err := c.Load()
if err != nil {
return err
}
// initialise tabwriter if nil
if *w == nil {
*w = tabwriter.NewWriter(os.Stdout, 0, 1, 4, ' ', 0)
// write header when initialising
if !fmsg.Verbose() {
_, _ = fmt.Fprintln(*w, "\tPID\tApp\tUptime\tEnablements\tCommand")
} else {
// argv is emitted in body when verbose
_, _ = fmt.Fprintln(*w, "\tPID\tApp\tArgv")
}
}
// print each state
for _, state := range states {
// skip nil states
if state == nil {
_, _ = fmt.Fprintln(*w, "\tnil state entry")
continue
}
// build enablements and command string
var (
ets *strings.Builder
cs = "(No command information)"
)
// check if enablements are provided
if state.Config != nil {
ets = new(strings.Builder)
// append enablement strings in order
for i := system.Enablement(0); i < system.Enablement(system.ELen); i++ {
if state.Config.Confinement.Enablements.Has(i) {
ets.WriteString(", " + i.String())
}
}
cs = fmt.Sprintf("%q", state.Config.Command)
}
if ets != nil {
// prevent an empty string
if ets.Len() == 0 {
ets.WriteString("(No enablements)")
}
} else {
ets = new(strings.Builder)
ets.WriteString("(No confinement information)")
}
if !fmsg.Verbose() {
_, _ = fmt.Fprintf(*w, "\t%d\t%d\t%s\t%s\t%s\n",
state.PID, aid, now.Sub(state.Time).Round(time.Second).String(), strings.TrimPrefix(ets.String(), ", "), cs)
} else {
// emit argv instead when verbose
_, _ = fmt.Fprintf(*w, "\t%d\t%d\t%s\n",
state.PID, aid, state.ID)
}
}
return nil
}()
}); err != nil {
fmsg.Printf("cannot perform action on app %d: %v", aid, err)
if !ok {
fmsg.Fatal("store faulted before printing")
}
}
if innerErr != nil {
fmsg.Fatalf("cannot print launcher state of app %d: %s", aid, innerErr)
}
}

16
main.go
View File

@ -112,16 +112,14 @@ func main() {
flag.CommandLine.Usage() flag.CommandLine.Usage()
fmsg.Exit(0) fmsg.Exit(0)
case "ps": // print all state info case "ps": // print all state info
var w *tabwriter.Writer set := flag.NewFlagSet("ps", flag.ExitOnError)
state.MustPrintLauncherStateSimpleGlobal(&w, os.Paths().RunDirPath) var short bool
if w != nil { set.BoolVar(&short, "short", false, "Print instance id")
if err := w.Flush(); err != nil {
fmsg.Println("cannot format output:", err)
}
} else {
fmt.Println("No information available")
}
// Ignore errors; set is set for ExitOnError.
_ = set.Parse(args[1:])
printPs(short)
fmsg.Exit(0) fmsg.Exit(0)
case "show": // pretty-print app info case "show": // pretty-print app info
if len(args) != 2 { if len(args) != 2 {

View File

@ -4,6 +4,7 @@ import (
"encoding/json" "encoding/json"
"fmt" "fmt"
direct "os" direct "os"
"strconv"
"strings" "strings"
"text/tabwriter" "text/tabwriter"
"time" "time"
@ -138,6 +139,78 @@ func printShow(instance *state.State, config *fst.Config) {
} }
} }
func printPs(short bool) {
now := time.Now().UTC()
var entries state.Entries
s := state.NewMulti(os.Paths().RunDirPath)
if e, err := state.Join(s); err != nil {
fmsg.Fatalf("cannot join store: %v", err)
} else {
entries = e
}
if err := s.Close(); err != nil {
fmsg.Printf("cannot close store: %v", err)
}
if short {
var v []string
if flagJSON {
v = make([]string, 0, len(entries))
}
for _, instance := range entries {
if !flagJSON {
fmt.Println(instance.ID.String())
} else {
v = append(v, instance.ID.String())
}
}
if flagJSON {
printJSON(v)
}
return
}
if flagJSON {
printJSON(entries)
return
}
// buffer output to reduce terminal activity
w := tabwriter.NewWriter(direct.Stdout, 0, 1, 4, ' ', 0)
fmt.Fprintln(w, "\tInstance\tPID\tApp\tUptime\tEnablements\tCommand")
for _, instance := range entries {
printInstance(w, instance, now)
}
if err := w.Flush(); err != nil {
fmsg.Fatalf("cannot flush tabwriter: %v", err)
}
}
func printInstance(w *tabwriter.Writer, instance *state.State, now time.Time) {
// gracefully skip nil states
if instance == nil {
fmsg.Println("got invalid state entry")
return
}
var (
es = "(No confinement information)"
cs = "(No command information)"
as = "(No configuration information)"
)
if instance.Config != nil {
es = instance.Config.Confinement.Enablements.String()
cs = fmt.Sprintf("%q", instance.Config.Command)
as = strconv.Itoa(instance.Config.Confinement.AppID)
}
fmt.Fprintf(w, "\t%s\t%d\t%s\t%s\t%s\t%s\n",
instance.ID.String()[:8], instance.PID, as, now.Sub(instance.Time).Round(time.Second).String(), strings.TrimPrefix(es, ", "), cs)
}
func printJSON(v any) { func printJSON(v any) {
encoder := json.NewEncoder(direct.Stdout) encoder := json.NewEncoder(direct.Stdout)
encoder.SetIndent("", " ") encoder.SetIndent("", " ")