Ophestra Umiker
eae3034260
Fortify state store instances was specific to aids due to outdated design decisions carried over from the ego rewrite. That no longer makes sense in the current application, so the interface now enables a single store object to manage all transient state. Signed-off-by: Ophestra Umiker <cat@ophivana.moe>
119 lines
3.0 KiB
Go
119 lines
3.0 KiB
Go
package state
|
|
|
|
import (
|
|
"fmt"
|
|
"os"
|
|
"strings"
|
|
"text/tabwriter"
|
|
"time"
|
|
|
|
"git.ophivana.moe/security/fortify/internal/fmsg"
|
|
"git.ophivana.moe/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)
|
|
}
|
|
}
|