diff options
| author | Ophestra Umiker <cat@ophivana.moe> | 2024-09-17 13:48:42 +0900 |
|---|---|---|
| committer | Ophestra Umiker <cat@ophivana.moe> | 2024-09-17 13:48:42 +0900 |
| commit | 4b7d616862dc7d8c73561b85deb0ca1fabf30781 (patch) | |
| tree | d069af086d1fcfeca2f9a629e0f3eb3e2f19500f /internal/app | |
| parent | 6a6f62efa672bdb439c2f9056055193a53c1df01 (diff) | |
exit: move final and early code to internal package
Exit cleanup state information is now stored in a dedicated struct and built up using methods of that struct.
Signed-off-by: Ophestra Umiker <cat@ophivana.moe>
Diffstat (limited to 'internal/app')
| -rw-r--r-- | internal/app/dbus.go | 23 | ||||
| -rw-r--r-- | internal/app/ensure.go | 22 | ||||
| -rw-r--r-- | internal/app/launch.go | 4 | ||||
| -rw-r--r-- | internal/app/pulse.go | 76 | ||||
| -rw-r--r-- | internal/app/run.go | 20 | ||||
| -rw-r--r-- | internal/app/setup.go | 21 | ||||
| -rw-r--r-- | internal/app/wayland.go | 11 | ||||
| -rw-r--r-- | internal/app/x.go | 11 |
8 files changed, 119 insertions, 69 deletions
diff --git a/internal/app/dbus.go b/internal/app/dbus.go index a327e2cd..fe8039f6 100644 --- a/internal/app/dbus.go +++ b/internal/app/dbus.go @@ -9,8 +9,7 @@ import ( "git.ophivana.moe/cat/fortify/acl" "git.ophivana.moe/cat/fortify/dbus" - "git.ophivana.moe/cat/fortify/internal/final" - "git.ophivana.moe/cat/fortify/internal/state" + "git.ophivana.moe/cat/fortify/internal" "git.ophivana.moe/cat/fortify/internal/util" "git.ophivana.moe/cat/fortify/internal/verbose" ) @@ -26,7 +25,7 @@ var ( ) func (a *App) ShareDBus(dse, dsg *dbus.Config, log bool) { - a.setEnablement(state.EnableDBus) + a.setEnablement(internal.EnableDBus) dbusSystem = dsg != nil var binPath string @@ -41,7 +40,7 @@ func (a *App) ShareDBus(dse, dsg *dbus.Config, log bool) { } if b, ok := util.Which("xdg-dbus-proxy"); !ok { - final.Fatal("D-Bus: Did not find 'xdg-dbus-proxy' in PATH") + internal.Fatal("D-Bus: Did not find 'xdg-dbus-proxy' in PATH") } else { binPath = b } @@ -69,7 +68,7 @@ func (a *App) ShareDBus(dse, dsg *dbus.Config, log bool) { verbose.Println("D-Bus: sealing system proxy", dsg.Args(systemBus)) } if err := p.Seal(dse, dsg); err != nil { - final.Fatal("D-Bus: invalid config when sealing proxy,", err) + internal.Fatal("D-Bus: invalid config when sealing proxy,", err) } ready := make(chan bool, 1) @@ -80,7 +79,7 @@ func (a *App) ShareDBus(dse, dsg *dbus.Config, log bool) { verbose.Printf("Starting system bus proxy '%s' for address '%s'\n", dbusAddress[1], systemBus[0]) } if err := p.Start(&ready); err != nil { - final.Fatal("D-Bus: error starting proxy,", err) + internal.Fatal("D-Bus: error starting proxy,", err) } verbose.Println("D-Bus proxy launch:", p) @@ -97,24 +96,24 @@ func (a *App) ShareDBus(dse, dsg *dbus.Config, log bool) { }() // register early to enable Fatal cleanup - final.RegisterDBus(p, &done) + a.exit.SealDBus(p, &done) if !<-ready { - final.Fatal("D-Bus: proxy did not start correctly") + internal.Fatal("D-Bus: proxy did not start correctly") } a.AppendEnv(dbusSessionBusAddress, dbusAddress[0]) if err := acl.UpdatePerm(sessionBus[1], a.UID(), acl.Read, acl.Write); err != nil { - final.Fatal(fmt.Sprintf("Error preparing D-Bus session proxy '%s':", dbusAddress[0]), err) + internal.Fatal(fmt.Sprintf("Error preparing D-Bus session proxy '%s':", dbusAddress[0]), err) } else { - final.RegisterRevertPath(sessionBus[1]) + a.exit.RegisterRevertPath(sessionBus[1]) } if dsg != nil { a.AppendEnv(dbusSystemBusAddress, dbusAddress[1]) if err := acl.UpdatePerm(systemBus[1], a.UID(), acl.Read, acl.Write); err != nil { - final.Fatal(fmt.Sprintf("Error preparing D-Bus system proxy '%s':", dbusAddress[1]), err) + internal.Fatal(fmt.Sprintf("Error preparing D-Bus system proxy '%s':", dbusAddress[1]), err) } else { - final.RegisterRevertPath(systemBus[1]) + a.exit.RegisterRevertPath(systemBus[1]) } } verbose.Printf("Session bus proxy '%s' for address '%s' configured\n", dbusAddress[0], sessionBus[0]) diff --git a/internal/app/ensure.go b/internal/app/ensure.go index ada6349f..ed283a94 100644 --- a/internal/app/ensure.go +++ b/internal/app/ensure.go @@ -8,29 +8,29 @@ import ( "path" "git.ophivana.moe/cat/fortify/acl" - "git.ophivana.moe/cat/fortify/internal/final" + "git.ophivana.moe/cat/fortify/internal" "git.ophivana.moe/cat/fortify/internal/verbose" ) func (a *App) EnsureRunDir() { if err := os.Mkdir(a.runDirPath, 0700); err != nil && !errors.Is(err, fs.ErrExist) { - final.Fatal("Error creating runtime directory:", err) + internal.Fatal("Error creating runtime directory:", err) } } func (a *App) EnsureRuntime() { if s, err := os.Stat(a.runtimePath); err != nil { if errors.Is(err, fs.ErrNotExist) { - final.Fatal("Runtime directory does not exist") + internal.Fatal("Runtime directory does not exist") } - final.Fatal("Error accessing runtime directory:", err) + internal.Fatal("Error accessing runtime directory:", err) } else if !s.IsDir() { - final.Fatal(fmt.Sprintf("Path '%s' is not a directory", a.runtimePath)) + internal.Fatal(fmt.Sprintf("Path '%s' is not a directory", a.runtimePath)) } else { if err = acl.UpdatePerm(a.runtimePath, a.UID(), acl.Execute); err != nil { - final.Fatal("Error preparing runtime directory:", err) + internal.Fatal("Error preparing runtime directory:", err) } else { - final.RegisterRevertPath(a.runtimePath) + a.exit.RegisterRevertPath(a.runtimePath) } verbose.Printf("Runtime data dir '%s' configured\n", a.runtimePath) } @@ -39,7 +39,7 @@ func (a *App) EnsureRuntime() { func (a *App) EnsureShare() { // acl is unnecessary as this directory is world executable if err := os.Mkdir(a.sharePath, 0701); err != nil && !errors.Is(err, fs.ErrExist) { - final.Fatal("Error creating shared directory:", err) + internal.Fatal("Error creating shared directory:", err) } // workaround for launch method sudo @@ -47,12 +47,12 @@ func (a *App) EnsureShare() { // ensure child runtime directory (e.g. `/tmp/fortify.%d/%d.share`) cr := path.Join(a.sharePath, a.Uid+".share") if err := os.Mkdir(cr, 0700); err != nil && !errors.Is(err, fs.ErrExist) { - final.Fatal("Error creating child runtime directory:", err) + internal.Fatal("Error creating child runtime directory:", err) } else { if err = acl.UpdatePerm(cr, a.UID(), acl.Read, acl.Write, acl.Execute); err != nil { - final.Fatal("Error preparing child runtime directory:", err) + internal.Fatal("Error preparing child runtime directory:", err) } else { - final.RegisterRevertPath(cr) + a.exit.RegisterRevertPath(cr) } a.AppendEnv("XDG_RUNTIME_DIR", cr) a.AppendEnv("XDG_SESSION_CLASS", "user") diff --git a/internal/app/launch.go b/internal/app/launch.go index 886e683c..b44c7785 100644 --- a/internal/app/launch.go +++ b/internal/app/launch.go @@ -5,11 +5,11 @@ import ( "encoding/base64" "encoding/gob" "fmt" - "git.ophivana.moe/cat/fortify/internal/final" "os" "strings" "syscall" + "git.ophivana.moe/cat/fortify/internal" "git.ophivana.moe/cat/fortify/internal/util" ) @@ -20,7 +20,7 @@ func (a *App) launcherPayloadEnv() string { enc := base64.NewEncoder(base64.StdEncoding, r) if err := gob.NewEncoder(enc).Encode(a.command); err != nil { - final.Fatal("Error encoding launcher payload:", err) + internal.Fatal("Error encoding launcher payload:", err) } _ = enc.Close() diff --git a/internal/app/pulse.go b/internal/app/pulse.go index 7c360252..8b4921ed 100644 --- a/internal/app/pulse.go +++ b/internal/app/pulse.go @@ -8,58 +8,102 @@ import ( "path" "git.ophivana.moe/cat/fortify/acl" - "git.ophivana.moe/cat/fortify/internal/final" - "git.ophivana.moe/cat/fortify/internal/state" + "git.ophivana.moe/cat/fortify/internal" "git.ophivana.moe/cat/fortify/internal/util" "git.ophivana.moe/cat/fortify/internal/verbose" ) +const ( + pulseServer = "PULSE_SERVER" + pulseCookie = "PULSE_COOKIE" + + home = "HOME" + xdgConfigHome = "XDG_CONFIG_HOME" +) + func (a *App) SharePulse() { - a.setEnablement(state.EnablePulse) + a.setEnablement(internal.EnablePulse) // ensure PulseAudio directory ACL (e.g. `/run/user/%d/pulse`) pulse := path.Join(a.runtimePath, "pulse") pulseS := path.Join(pulse, "native") if s, err := os.Stat(pulse); err != nil { if !errors.Is(err, fs.ErrNotExist) { - final.Fatal("Error accessing PulseAudio directory:", err) + internal.Fatal("Error accessing PulseAudio directory:", err) } - final.Fatal(fmt.Sprintf("PulseAudio dir '%s' not found", pulse)) + internal.Fatal(fmt.Sprintf("PulseAudio dir '%s' not found", pulse)) } else { // add environment variable for new process - a.AppendEnv(util.PulseServer, "unix:"+pulseS) + a.AppendEnv(pulseServer, "unix:"+pulseS) if err = acl.UpdatePerm(pulse, a.UID(), acl.Execute); err != nil { - final.Fatal("Error preparing PulseAudio:", err) + internal.Fatal("Error preparing PulseAudio:", err) } else { - final.RegisterRevertPath(pulse) + a.exit.RegisterRevertPath(pulse) } // ensure PulseAudio socket permission (e.g. `/run/user/%d/pulse/native`) if s, err = os.Stat(pulseS); err != nil { if errors.Is(err, fs.ErrNotExist) { - final.Fatal("PulseAudio directory found but socket does not exist") + internal.Fatal("PulseAudio directory found but socket does not exist") } - final.Fatal("Error accessing PulseAudio socket:", err) + internal.Fatal("Error accessing PulseAudio socket:", err) } else { if m := s.Mode(); m&0o006 != 0o006 { - final.Fatal(fmt.Sprintf("Unexpected permissions on '%s':", pulseS), m) + internal.Fatal(fmt.Sprintf("Unexpected permissions on '%s':", pulseS), m) } } // Publish current user's pulse-cookie for target user - pulseCookieSource := util.DiscoverPulseCookie() + pulseCookieSource := discoverPulseCookie() pulseCookieFinal := path.Join(a.sharePath, "pulse-cookie") - a.AppendEnv(util.PulseCookie, pulseCookieFinal) + a.AppendEnv(pulseCookie, pulseCookieFinal) verbose.Printf("Publishing PulseAudio cookie '%s' to '%s'\n", pulseCookieSource, pulseCookieFinal) if err = util.CopyFile(pulseCookieFinal, pulseCookieSource); err != nil { - final.Fatal("Error copying PulseAudio cookie:", err) + internal.Fatal("Error copying PulseAudio cookie:", err) } if err = acl.UpdatePerm(pulseCookieFinal, a.UID(), acl.Read); err != nil { - final.Fatal("Error publishing PulseAudio cookie:", err) + internal.Fatal("Error publishing PulseAudio cookie:", err) } else { - final.RegisterRevertPath(pulseCookieFinal) + a.exit.RegisterRevertPath(pulseCookieFinal) } verbose.Printf("PulseAudio dir '%s' configured\n", pulse) } } + +// discoverPulseCookie try various standard methods to discover the current user's PulseAudio authentication cookie +func discoverPulseCookie() string { + if p, ok := os.LookupEnv(pulseCookie); ok { + return p + } + + if p, ok := os.LookupEnv(home); ok { + p = path.Join(p, ".pulse-cookie") + if s, err := os.Stat(p); err != nil { + if !errors.Is(err, fs.ErrNotExist) { + internal.Fatal("Error accessing PulseAudio cookie:", err) + // unreachable + return p + } + } else if !s.IsDir() { + return p + } + } + + if p, ok := os.LookupEnv(xdgConfigHome); ok { + p = path.Join(p, "pulse", "cookie") + if s, err := os.Stat(p); err != nil { + if !errors.Is(err, fs.ErrNotExist) { + internal.Fatal("Error accessing PulseAudio cookie:", err) + // unreachable + return p + } + } else if !s.IsDir() { + return p + } + } + + internal.Fatal(fmt.Sprintf("Cannot locate PulseAudio cookie (tried $%s, $%s/pulse/cookie, $%s/.pulse-cookie)", + pulseCookie, xdgConfigHome, home)) + return "" +} diff --git a/internal/app/run.go b/internal/app/run.go index d4a9e13c..cc01f487 100644 --- a/internal/app/run.go +++ b/internal/app/run.go @@ -3,11 +3,11 @@ package app import ( "errors" "fmt" - "git.ophivana.moe/cat/fortify/internal/final" "os" "os/exec" "strings" + "git.ophivana.moe/cat/fortify/internal" "git.ophivana.moe/cat/fortify/internal/state" "git.ophivana.moe/cat/fortify/internal/util" "git.ophivana.moe/cat/fortify/internal/verbose" @@ -52,28 +52,28 @@ func (a *App) Run() { verbose.Println("Executing:", cmd) if err := cmd.Start(); err != nil { - final.Fatal("Error starting process:", err) + internal.Fatal("Error starting process:", err) } - final.RegisterEnablement(a.enablements) + a.exit.SealEnablements(a.enablements) if statePath, err := state.SaveProcess(a.Uid, cmd, a.runDirPath, a.command, a.enablements); err != nil { // process already started, shouldn't be fatal fmt.Println("Error registering process:", err) } else { - final.RegisterStatePath(statePath) + a.exit.SealStatePath(statePath) } var r int if err := cmd.Wait(); err != nil { var exitError *exec.ExitError if !errors.As(err, &exitError) { - final.Fatal("Error running process:", err) + internal.Fatal("Error running process:", err) } } verbose.Println("Process exited with exit code", r) - final.BeforeExit() + internal.BeforeExit() os.Exit(r) } @@ -101,7 +101,7 @@ func (a *App) commandBuilderSudo() (args []string) { func (a *App) commandBuilderBwrap() (args []string) { // TODO: build bwrap command - final.Fatal("bwrap") + internal.Fatal("bwrap") panic("unreachable") } @@ -129,7 +129,7 @@ func (a *App) commandBuilderMachineCtl() (args []string) { // /bin/sh -c if sh, ok := util.Which("sh"); !ok { - final.Fatal("Did not find 'sh' in PATH") + internal.Fatal("Did not find 'sh' in PATH") } else { args = append(args, sh, "-c") } @@ -147,9 +147,9 @@ func (a *App) commandBuilderMachineCtl() (args []string) { innerCommand.WriteString("; ") if executable, err := os.Executable(); err != nil { - final.Fatal("Error reading executable path:", err) + internal.Fatal("Error reading executable path:", err) } else { - if a.enablements.Has(state.EnableDBus) { + if a.enablements.Has(internal.EnableDBus) { innerCommand.WriteString(dbusSessionBusAddress + "=" + "'" + dbusAddress[0] + "' ") if dbusSystem { innerCommand.WriteString(dbusSystemBusAddress + "=" + "'" + dbusAddress[1] + "' ") diff --git a/internal/app/setup.go b/internal/app/setup.go index 8d6eb881..c13468a0 100644 --- a/internal/app/setup.go +++ b/internal/app/setup.go @@ -8,7 +8,7 @@ import ( "path" "strconv" - "git.ophivana.moe/cat/fortify/internal/state" + "git.ophivana.moe/cat/fortify/internal" "git.ophivana.moe/cat/fortify/internal/util" "git.ophivana.moe/cat/fortify/internal/verbose" ) @@ -22,6 +22,8 @@ type App struct { env []string // modified via AppendEnv command []string // set on initialisation + exit *internal.ExitState // assigned + launchOptionText string // set on initialisation launchOption uint8 // assigned @@ -30,8 +32,8 @@ type App struct { runDirPath string // assigned toolPath string // assigned - enablements state.Enablements // set via setEnablement - *user.User // assigned + enablements internal.Enablements // set via setEnablement + *user.User // assigned // absolutely *no* method of this type is thread-safe // so don't treat it as if it is @@ -45,7 +47,7 @@ func (a *App) RunDir() string { return a.runDirPath } -func (a *App) setEnablement(e state.Enablement) { +func (a *App) setEnablement(e internal.Enablement) { if a.enablements.Has(e) { panic("enablement " + e.String() + " set twice") } @@ -53,6 +55,13 @@ func (a *App) setEnablement(e state.Enablement) { a.enablements |= e.Mask() } +func (a *App) SealExit(exit *internal.ExitState) { + if a.exit != nil { + panic("application exit state sealed twice") + } + a.exit = exit +} + func New(userName string, args []string, launchOptionText string) *App { a := &App{ command: args, @@ -96,7 +105,7 @@ func New(userName string, args []string, launchOptionText string) *App { } verbose.Println("Running as user", a.Username, "("+a.Uid+"),", "command:", a.command) - if util.SdBootedV { + if internal.SdBootedV { verbose.Println("System booted with systemd as init system (PID 1).") } @@ -120,7 +129,7 @@ func New(userName string, args []string, launchOptionText string) *App { } case "systemd": a.launchOption = LaunchMethodMachineCtl - if !util.SdBootedV { + if !internal.SdBootedV { fmt.Println("System has not been booted with systemd as init system (PID 1).") os.Exit(1) } diff --git a/internal/app/wayland.go b/internal/app/wayland.go index 3b12e3ec..33ed9914 100644 --- a/internal/app/wayland.go +++ b/internal/app/wayland.go @@ -6,8 +6,7 @@ import ( "path" "git.ophivana.moe/cat/fortify/acl" - "git.ophivana.moe/cat/fortify/internal/final" - "git.ophivana.moe/cat/fortify/internal/state" + "git.ophivana.moe/cat/fortify/internal" "git.ophivana.moe/cat/fortify/internal/verbose" ) @@ -17,19 +16,19 @@ const ( ) func (a *App) ShareWayland() { - a.setEnablement(state.EnableWayland) + a.setEnablement(internal.EnableWayland) // ensure Wayland socket ACL (e.g. `/run/user/%d/wayland-%d`) if w, ok := os.LookupEnv(waylandDisplay); !ok { - final.Fatal("Wayland: WAYLAND_DISPLAY not set") + internal.Fatal("Wayland: WAYLAND_DISPLAY not set") } else { // add environment variable for new process wp := path.Join(a.runtimePath, w) a.AppendEnv(waylandDisplay, wp) if err := acl.UpdatePerm(wp, a.UID(), acl.Read, acl.Write, acl.Execute); err != nil { - final.Fatal(fmt.Sprintf("Error preparing Wayland '%s':", w), err) + internal.Fatal(fmt.Sprintf("Error preparing Wayland '%s':", w), err) } else { - final.RegisterRevertPath(wp) + a.exit.RegisterRevertPath(wp) } verbose.Printf("Wayland socket '%s' configured\n", w) } diff --git a/internal/app/x.go b/internal/app/x.go index f198fee3..16b3d95c 100644 --- a/internal/app/x.go +++ b/internal/app/x.go @@ -4,8 +4,7 @@ import ( "fmt" "os" - "git.ophivana.moe/cat/fortify/internal/final" - "git.ophivana.moe/cat/fortify/internal/state" + "git.ophivana.moe/cat/fortify/internal" "git.ophivana.moe/cat/fortify/internal/verbose" "git.ophivana.moe/cat/fortify/xcb" ) @@ -13,20 +12,20 @@ import ( const display = "DISPLAY" func (a *App) ShareX() { - a.setEnablement(state.EnableX) + a.setEnablement(internal.EnableX) // discovery X11 and grant user permission via the `ChangeHosts` command if d, ok := os.LookupEnv(display); !ok { - final.Fatal("X11: DISPLAY not set") + internal.Fatal("X11: DISPLAY not set") } else { // add environment variable for new process a.AppendEnv(display, d) verbose.Printf("X11: Adding XHost entry SI:localuser:%s to display '%s'\n", a.Username, d) if err := xcb.ChangeHosts(xcb.HostModeInsert, xcb.FamilyServerInterpreted, "localuser\x00"+a.Username); err != nil { - final.Fatal(fmt.Sprintf("Error adding XHost entry to '%s':", d), err) + internal.Fatal(fmt.Sprintf("Error adding XHost entry to '%s':", d), err) } else { - final.XcbActionComplete() + a.exit.XcbActionComplete() } } } |
