aboutsummaryrefslogtreecommitdiffhomepage
path: root/main.go
diff options
context:
space:
mode:
Diffstat (limited to 'main.go')
-rw-r--r--main.go193
1 files changed, 123 insertions, 70 deletions
diff --git a/main.go b/main.go
index c35e4251..cc1809f6 100644
--- a/main.go
+++ b/main.go
@@ -5,10 +5,7 @@ import (
"errors"
"flag"
"fmt"
- "io/fs"
"os"
- "strconv"
- "syscall"
"git.ophivana.moe/cat/fortify/dbus"
"git.ophivana.moe/cat/fortify/internal"
@@ -19,14 +16,6 @@ import (
var (
Version = "impure"
-
- a *app.App
- s *internal.ExitState
-
- dbusSession *dbus.Config
- dbusSystem *dbus.Config
-
- launchOptionText string
)
func tryVersion() {
@@ -40,94 +29,158 @@ func main() {
flag.Parse()
verbose.Set(flagVerbose)
+ if internal.SdBootedV {
+ verbose.Println("system booted with systemd as init system")
+ }
+
// launcher payload early exit
- app.Early(printVersion)
+ if printVersion && printLicense {
+ app.TryShim()
+ }
// version/license command early exit
tryVersion()
tryLicense()
- a = app.New(userName, flag.Args(), launchOptionText)
- s = internal.NewExit(a.User, a.UID(), func() (int, error) {
- d, err := state.ReadLaunchers(a.RunDir(), a.Uid, false)
- return len(d), err
- })
- a.SealExit(s)
- internal.SealExit(s)
+ // state query command early exit
+ tryState()
- // parse D-Bus config file if applicable
- if mustDBus {
- if dbusConfigSession == "builtin" {
- dbusSession = dbus.NewConfig(dbusID, true, mpris)
+ // prepare config
+ var config *app.Config
+
+ if confPath == "nil" {
+ // config from flags
+ config = configFromFlags()
+ } else {
+ // config from file
+ if f, err := os.Open(confPath); err != nil {
+ fatalf("cannot access config file '%s': %s\n", confPath, err)
} else {
- if f, err := os.Open(dbusConfigSession); err != nil {
- internal.Fatal("Error opening D-Bus proxy config file:", err)
- } else {
- if err = json.NewDecoder(f).Decode(&dbusSession); err != nil {
- internal.Fatal("Error parsing D-Bus proxy config file:", err)
- }
+ if err = json.NewDecoder(f).Decode(&config); err != nil {
+ fatalf("cannot parse config file '%s': %s\n", confPath, err)
}
}
+ }
- // system bus proxy is optional
- if dbusConfigSystem != "nil" {
- if f, err := os.Open(dbusConfigSystem); err != nil {
- internal.Fatal("Error opening D-Bus proxy config file:", err)
+ // invoke app
+ r := 1
+ a := app.New()
+ if err := a.Seal(config); err != nil {
+ logBaseError(err, "fortify: cannot seal app:")
+ } else if err = a.Start(); err != nil {
+ logBaseError(err, "fortify: cannot start app:")
+ } else if r, err = a.Wait(); err != nil {
+ r = 1
+
+ var e *app.BaseError
+ if !app.AsBaseError(err, &e) {
+ fmt.Println("fortify: wait failed:", err)
+ } else {
+ // Wait only returns either *app.ProcessError or *app.StateStoreError wrapped in a *app.BaseError
+ var se *app.StateStoreError
+ if !errors.As(err, &se) {
+ // does not need special handling
+ fmt.Print("fortify: " + e.Message())
} else {
- if err = json.NewDecoder(f).Decode(&dbusSystem); err != nil {
- internal.Fatal("Error parsing D-Bus proxy config file:", err)
+ // inner error are either unwrapped store errors
+ // or joined errors returned by *appSealTx revert
+ // wrapped in *app.BaseError
+ var ej app.RevertCompoundError
+ if !errors.As(se.InnerErr, &ej) {
+ // does not require special handling
+ fmt.Print("fortify: " + e.Message())
+ } else {
+ errs := ej.Unwrap()
+
+ // every error here is wrapped in *app.BaseError
+ for _, ei := range errs {
+ var eb *app.BaseError
+ if !errors.As(ei, &eb) {
+ // unreachable
+ fmt.Println("fortify: invalid error type returned by revert:", ei)
+ } else {
+ // print inner *app.BaseError message
+ fmt.Print("fortify: " + eb.Message())
+ }
+ }
}
}
}
}
+ if err := a.WaitErr(); err != nil {
+ fmt.Println("fortify: inner wait failed:", err)
+ }
+ os.Exit(r)
+}
- // ensure RunDir (e.g. `/run/user/%d/fortify`)
- a.EnsureRunDir()
-
- // state query command early exit
- tryState()
-
- // ensure Share (e.g. `/tmp/fortify.%d`)
- a.EnsureShare()
+func logBaseError(err error, message string) {
+ var e *app.BaseError
- // warn about target user home directory ownership
- if stat, err := os.Stat(a.HomeDir); err != nil {
- if verbose.Get() {
- switch {
- case errors.Is(err, fs.ErrPermission):
- fmt.Printf("User %s home directory %s is not accessible\n", a.Username, a.HomeDir)
- case errors.Is(err, fs.ErrNotExist):
- fmt.Printf("User %s home directory %s does not exis\n", a.Username, a.HomeDir)
- default:
- fmt.Printf("Error stat user %s home directory %s: %s\n", a.Username, a.HomeDir, err)
- }
- }
- return
+ if app.AsBaseError(err, &e) {
+ fmt.Print("fortify: " + e.Message())
} else {
- // FreeBSD: not cross-platform
- if u := strconv.Itoa(int(stat.Sys().(*syscall.Stat_t).Uid)); u != a.Uid {
- fmt.Printf("User %s home directory %s has incorrect ownership (expected UID %s, found %s)", a.Username, a.HomeDir, a.Uid, u)
- }
+ fmt.Println(message, err)
}
+}
- // ensure runtime directory ACL (e.g. `/run/user/%d`)
- a.EnsureRuntime()
+func configFromFlags() (config *app.Config) {
+ // initialise config from flags
+ config = &app.Config{
+ ID: dbusID,
+ User: userName,
+ Command: flag.Args(),
+ Method: launchMethodText,
+ }
+ // enablements from flags
if mustWayland {
- a.ShareWayland()
+ config.Confinement.Enablements.Set(state.EnableWayland)
}
-
if mustX {
- a.ShareX()
+ config.Confinement.Enablements.Set(state.EnableX)
}
-
if mustDBus {
- a.ShareDBus(dbusSession, dbusSystem, dbusVerbose)
+ config.Confinement.Enablements.Set(state.EnableDBus)
}
-
if mustPulse {
- a.SharePulse()
+ config.Confinement.Enablements.Set(state.EnablePulse)
}
- a.Run()
+ // parse D-Bus config file from flags if applicable
+ if mustDBus {
+ if dbusConfigSession == "builtin" {
+ config.Confinement.SessionBus = dbus.NewConfig(dbusID, true, mpris)
+ } else {
+ if f, err := os.Open(dbusConfigSession); err != nil {
+ fatalf("cannot access session bus proxy config file '%s': %s\n", dbusConfigSession, err)
+ } else {
+ if err = json.NewDecoder(f).Decode(&config.Confinement.SessionBus); err != nil {
+ fatalf("cannot parse session bus proxy config file '%s': %s\n", dbusConfigSession, err)
+ }
+ }
+ }
+
+ // system bus proxy is optional
+ if dbusConfigSystem != "nil" {
+ if f, err := os.Open(dbusConfigSystem); err != nil {
+ fatalf("cannot access system bus proxy config file '%s': %s\n", dbusConfigSystem, err)
+ } else {
+ if err = json.NewDecoder(f).Decode(&config.Confinement.SystemBus); err != nil {
+ fatalf("cannot parse system bus proxy config file '%s': %s\n", dbusConfigSystem, err)
+ }
+ }
+ }
+
+ if dbusVerbose {
+ config.Confinement.SessionBus.Log = true
+ config.Confinement.SystemBus.Log = true
+ }
+ }
+
+ return
+}
+
+func fatalf(format string, a ...any) {
+ fmt.Printf("fortify: "+format, a...)
+ os.Exit(1)
}