diff options
Diffstat (limited to 'internal/state/track.go')
| -rw-r--r-- | internal/state/track.go | 115 |
1 files changed, 115 insertions, 0 deletions
diff --git a/internal/state/track.go b/internal/state/track.go new file mode 100644 index 00000000..913d684d --- /dev/null +++ b/internal/state/track.go @@ -0,0 +1,115 @@ +package state + +import ( + "encoding/gob" + "errors" + "flag" + "fmt" + "io/fs" + "os" + "os/exec" + "path" + "strconv" + + "git.ophivana.moe/cat/fortify/internal/system" +) + +// we unfortunately have to assume there are never races between processes +// this and launcher should eventually be replaced by a server process + +var ( + stateActionEarly bool + statePath string + cleanupCandidate []string + xcbActionComplete bool +) + +type launcherState struct { + PID int + Launcher string + Argv []string + Command []string +} + +func init() { + flag.BoolVar(&stateActionEarly, "state", false, "query state value of current active launchers") +} + +func Early() { + if !stateActionEarly { + return + } + + launchers, err := readLaunchers() + if err != nil { + fmt.Println("Error reading launchers:", err) + os.Exit(1) + } + + fmt.Println("\tPID\tLauncher") + for _, state := range launchers { + fmt.Printf("\t%d\t%s\nCommand: %s\nArgv: %s\n", state.PID, state.Launcher, state.Command, state.Argv) + } + + os.Exit(0) +} + +// SaveProcess called after process start, before wait +func SaveProcess(uid string, cmd *exec.Cmd) error { + statePath = path.Join(system.V.RunDir, uid, strconv.Itoa(cmd.Process.Pid)) + state := launcherState{ + PID: cmd.Process.Pid, + Launcher: cmd.Path, + Argv: cmd.Args, + Command: command, + } + + if err := os.Mkdir(path.Join(system.V.RunDir, uid), 0700); err != nil && !errors.Is(err, fs.ErrExist) { + return err + } + + if f, err := os.OpenFile(statePath, os.O_RDWR|os.O_CREATE|os.O_EXCL, 0600); err != nil { + return err + } else { + defer func() { + if f.Close() != nil { + // unreachable + panic("state file closed prematurely") + } + }() + return gob.NewEncoder(f).Encode(state) + } +} + +func readLaunchers() ([]*launcherState, error) { + var f *os.File + var r []*launcherState + launcherPrefix := path.Join(system.V.RunDir, u.Uid) + + if pl, err := os.ReadDir(launcherPrefix); err != nil { + return nil, err + } else { + for _, e := range pl { + if err = func() error { + if f, err = os.Open(path.Join(launcherPrefix, e.Name())); err != nil { + return err + } else { + defer func() { + if f.Close() != nil { + // unreachable + panic("foreign state file closed prematurely") + } + }() + + var s launcherState + r = append(r, &s) + return gob.NewDecoder(f).Decode(&s) + } + }(); err != nil { + return nil, err + } + } + } + + return r, nil +} |
