aboutsummaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
authorOphestra <cat@gensokyo.uk>2025-02-26 17:36:14 +0900
committerOphestra <cat@gensokyo.uk>2025-02-26 17:36:14 +0900
commit840ceb615ae1fb6affcbe0a5774a5f4ca9d3c303 (patch)
tree62990268860457bb55c7ccf0e82354bef1bb266a
parent741d011543756850397ab7453cc13c9f5210e2b5 (diff)
app: handle RunState errors
Signed-off-by: Ophestra <cat@gensokyo.uk>
-rw-r--r--error.go46
-rw-r--r--internal/app/errors.go100
-rw-r--r--main.go67
3 files changed, 105 insertions, 108 deletions
diff --git a/error.go b/error.go
deleted file mode 100644
index 25c3cae2..00000000
--- a/error.go
+++ /dev/null
@@ -1,46 +0,0 @@
-package main
-
-import (
- "errors"
- "log"
-
- "git.gensokyo.uk/security/fortify/internal/app"
- "git.gensokyo.uk/security/fortify/internal/fmsg"
-)
-
-func logWaitError(err error) {
- var e *fmsg.BaseError
- if !fmsg.AsBaseError(err, &e) {
- log.Println("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
- log.Print(e.Message())
- } else {
- // 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
- log.Print(e.Message())
- } else {
- errs := ej.Unwrap()
-
- // every error here is wrapped in *app.BaseError
- for _, ei := range errs {
- var eb *fmsg.BaseError
- if !errors.As(ei, &eb) {
- // unreachable
- log.Println("invalid error type returned by revert:", ei)
- } else {
- // print inner *app.BaseError message
- log.Print(eb.Message())
- }
- }
- }
- }
- }
-}
diff --git a/internal/app/errors.go b/internal/app/errors.go
index c5209c46..6b5cffe4 100644
--- a/internal/app/errors.go
+++ b/internal/app/errors.go
@@ -2,10 +2,110 @@ package app
import (
"errors"
+ "log"
+ "git.gensokyo.uk/security/fortify/fst"
"git.gensokyo.uk/security/fortify/internal/fmsg"
)
+func PrintRunStateErr(rs *fst.RunState, runErr error) {
+ if runErr != nil {
+ if rs.Time == nil {
+ fmsg.PrintBaseError(runErr, "cannot start app:")
+ } else {
+ var e *fmsg.BaseError
+ if !fmsg.AsBaseError(runErr, &e) {
+ log.Println("wait failed:", runErr)
+ } else {
+ // Wait only returns either *app.ProcessError or *app.StateStoreError wrapped in a *app.BaseError
+ var se *StateStoreError
+ if !errors.As(runErr, &se) {
+ // does not need special handling
+ log.Print(e.Message())
+ } else {
+ // inner error are either unwrapped store errors
+ // or joined errors returned by *appSealTx revert
+ // wrapped in *app.BaseError
+ var ej RevertCompoundError
+ if !errors.As(se.InnerErr, &ej) {
+ // does not require special handling
+ log.Print(e.Message())
+ } else {
+ errs := ej.Unwrap()
+
+ // every error here is wrapped in *app.BaseError
+ for _, ei := range errs {
+ var eb *fmsg.BaseError
+ if !errors.As(ei, &eb) {
+ // unreachable
+ log.Println("invalid error type returned by revert:", ei)
+ } else {
+ // print inner *app.BaseError message
+ log.Print(eb.Message())
+ }
+ }
+ }
+ }
+ }
+ }
+
+ if rs.ExitCode == 0 {
+ rs.ExitCode = 126
+ }
+ }
+
+ if rs.RevertErr != nil {
+ var stateStoreError *StateStoreError
+ if !errors.As(rs.RevertErr, &stateStoreError) || stateStoreError == nil {
+ fmsg.PrintBaseError(rs.RevertErr, "generic fault during cleanup:")
+ goto out
+ }
+
+ if stateStoreError.Err != nil {
+ if len(stateStoreError.Err) == 2 {
+ if stateStoreError.Err[0] != nil {
+ if joinedErrs, ok := stateStoreError.Err[0].(interface{ Unwrap() []error }); !ok {
+ fmsg.PrintBaseError(stateStoreError.Err[0], "generic fault during revert:")
+ } else {
+ for _, err := range joinedErrs.Unwrap() {
+ if err != nil {
+ fmsg.PrintBaseError(err, "fault during revert:")
+ }
+ }
+ }
+ }
+ if stateStoreError.Err[1] != nil {
+ log.Printf("cannot close store: %v", stateStoreError.Err[1])
+ }
+ } else {
+ log.Printf("fault during cleanup: %v",
+ errors.Join(stateStoreError.Err...))
+ }
+ }
+
+ if stateStoreError.OpErr != nil {
+ log.Printf("blind revert due to store fault: %v",
+ stateStoreError.OpErr)
+ }
+
+ if stateStoreError.DoErr != nil {
+ fmsg.PrintBaseError(stateStoreError.DoErr, "state store operation unsuccessful:")
+ }
+
+ if stateStoreError.Inner && stateStoreError.InnerErr != nil {
+ fmsg.PrintBaseError(stateStoreError.InnerErr, "cannot destroy state entry:")
+ }
+
+ out:
+ if rs.ExitCode == 0 {
+ rs.ExitCode = 128
+ }
+ }
+ if rs.WaitErr != nil {
+ log.Println("inner wait failed:", rs.WaitErr)
+ }
+}
+
// StateStoreError is returned for a failed state save
type StateStoreError struct {
// whether inner function was called
diff --git a/main.go b/main.go
index 8df26592..3d3e4796 100644
--- a/main.go
+++ b/main.go
@@ -286,74 +286,17 @@ func buildCommand(out io.Writer) command.Command {
}
func runApp(a fst.App, config *fst.Config) {
- rs := new(fst.RunState)
ctx, stop := signal.NotifyContext(context.Background(),
syscall.SIGINT, syscall.SIGTERM)
defer stop() // unreachable
+ rs := new(fst.RunState)
if sa, err := a.Seal(config); err != nil {
fmsg.PrintBaseError(err, "cannot seal app:")
- internal.Exit(1)
- } else if err = sa.Run(ctx, rs); err != nil {
- if rs.Time == nil {
- fmsg.PrintBaseError(err, "cannot start app:")
- } else {
- logWaitError(err)
- }
-
- if rs.ExitCode == 0 {
- rs.ExitCode = 126
- }
- }
- if rs.RevertErr != nil {
- var stateStoreError *app.StateStoreError
- if !errors.As(rs.RevertErr, &stateStoreError) || stateStoreError == nil {
- fmsg.PrintBaseError(rs.RevertErr, "generic fault during cleanup:")
- goto out
- }
-
- if stateStoreError.Err != nil {
- if len(stateStoreError.Err) == 2 {
- if stateStoreError.Err[0] != nil {
- if joinedErrs, ok := stateStoreError.Err[0].(interface{ Unwrap() []error }); !ok {
- fmsg.PrintBaseError(stateStoreError.Err[0], "generic fault during revert:")
- } else {
- for _, err := range joinedErrs.Unwrap() {
- if err != nil {
- fmsg.PrintBaseError(err, "fault during revert:")
- }
- }
- }
- }
- if stateStoreError.Err[1] != nil {
- log.Printf("cannot close store: %v", stateStoreError.Err[1])
- }
- } else {
- log.Printf("fault during cleanup: %v",
- errors.Join(stateStoreError.Err...))
- }
- }
-
- if stateStoreError.OpErr != nil {
- log.Printf("blind revert due to store fault: %v",
- stateStoreError.OpErr)
- }
-
- if stateStoreError.DoErr != nil {
- fmsg.PrintBaseError(stateStoreError.DoErr, "state store operation unsuccessful:")
- }
-
- if stateStoreError.Inner && stateStoreError.InnerErr != nil {
- fmsg.PrintBaseError(stateStoreError.InnerErr, "cannot destroy state entry:")
- }
-
- out:
- if rs.ExitCode == 0 {
- rs.ExitCode = 128
- }
- }
- if rs.WaitErr != nil {
- log.Println("inner wait failed:", rs.WaitErr)
+ rs.ExitCode = 1
+ } else {
+ // this updates ExitCode
+ app.PrintRunStateErr(rs, sa.Run(ctx, rs))
}
internal.Exit(rs.ExitCode)
}