app: handle RunState errors
Signed-off-by: Ophestra <cat@gensokyo.uk>
This commit is contained in:
parent
741d011543
commit
840ceb615a
46
error.go
46
error.go
@ -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())
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -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
|
||||
|
67
main.go
67
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)
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user