aboutsummaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
-rw-r--r--cmd/fpkg/bundle.go12
-rw-r--r--cmd/fpkg/install.go38
-rw-r--r--cmd/fpkg/main.go14
-rw-r--r--cmd/fpkg/paths.go10
-rw-r--r--cmd/fpkg/proc.go21
-rw-r--r--cmd/fpkg/start.go9
-rw-r--r--cmd/fpkg/with.go4
-rw-r--r--error.go15
-rw-r--r--fst/sandbox.go10
-rw-r--r--helper/bwrap/config_test.go4
-rw-r--r--helper/seccomp/export_test.go4
-rw-r--r--helper/stub.go4
-rw-r--r--internal/app/init/early.go4
-rw-r--r--internal/app/init/main.go45
-rw-r--r--internal/app/seal.go4
-rw-r--r--internal/app/share.go6
-rw-r--r--internal/app/shim/main.go49
-rw-r--r--internal/app/shim/manager.go8
-rw-r--r--internal/app/start.go21
-rw-r--r--internal/executable.go (renamed from helper/proc/self.go)7
-rw-r--r--internal/exit.go9
-rw-r--r--internal/fmsg/defer.go98
-rw-r--r--internal/fmsg/fmsg.go88
-rw-r--r--internal/fmsg/verbose.go22
-rw-r--r--internal/linux/interface.go4
-rw-r--r--internal/linux/std.go12
-rw-r--r--internal/state/multi.go6
-rw-r--r--internal/system/acl.go6
-rw-r--r--internal/system/dbus.go21
-rw-r--r--internal/system/link.go6
-rw-r--r--internal/system/mkdir.go6
-rw-r--r--internal/system/op.go5
-rw-r--r--internal/system/tmpfiles.go6
-rw-r--r--internal/system/wayland.go10
-rw-r--r--internal/system/xhost.go6
-rw-r--r--main.go67
-rw-r--r--parse.go21
-rw-r--r--print.go30
38 files changed, 333 insertions, 379 deletions
diff --git a/cmd/fpkg/bundle.go b/cmd/fpkg/bundle.go
index 5c9db725..5692d5cb 100644
--- a/cmd/fpkg/bundle.go
+++ b/cmd/fpkg/bundle.go
@@ -2,10 +2,10 @@ package main
import (
"encoding/json"
+ "log"
"os"
"git.gensokyo.uk/security/fortify/dbus"
- "git.gensokyo.uk/security/fortify/internal/fmsg"
"git.gensokyo.uk/security/fortify/internal/system"
)
@@ -63,18 +63,18 @@ func loadBundleInfo(name string, beforeFail func()) *bundleInfo {
bundle := new(bundleInfo)
if f, err := os.Open(name); err != nil {
beforeFail()
- fmsg.Fatalf("cannot open bundle: %v", err)
+ log.Fatalf("cannot open bundle: %v", err)
} else if err = json.NewDecoder(f).Decode(&bundle); err != nil {
beforeFail()
- fmsg.Fatalf("cannot parse bundle metadata: %v", err)
+ log.Fatalf("cannot parse bundle metadata: %v", err)
} else if err = f.Close(); err != nil {
- fmsg.Printf("cannot close bundle metadata: %v", err)
+ log.Printf("cannot close bundle metadata: %v", err)
// not fatal
}
if bundle.ID == "" {
beforeFail()
- fmsg.Fatal("application identifier must not be empty")
+ log.Fatal("application identifier must not be empty")
}
return bundle
@@ -82,7 +82,7 @@ func loadBundleInfo(name string, beforeFail func()) *bundleInfo {
func formatHostname(name string) string {
if h, err := os.Hostname(); err != nil {
- fmsg.Printf("cannot get hostname: %v", err)
+ log.Printf("cannot get hostname: %v", err)
return "fortify-" + name
} else {
return h + "-" + name
diff --git a/cmd/fpkg/install.go b/cmd/fpkg/install.go
index 7c06461d..d1643b40 100644
--- a/cmd/fpkg/install.go
+++ b/cmd/fpkg/install.go
@@ -3,10 +3,12 @@ package main
import (
"encoding/json"
"flag"
+ "log"
"os"
"path"
"git.gensokyo.uk/security/fortify/fst"
+ "git.gensokyo.uk/security/fortify/internal"
"git.gensokyo.uk/security/fortify/internal/fmsg"
)
@@ -25,12 +27,12 @@ func actionInstall(args []string) {
args = set.Args()
if len(args) != 1 {
- fmsg.Fatal("invalid argument")
+ log.Fatal("invalid argument")
}
pkgPath := args[0]
if !path.IsAbs(pkgPath) {
if dir, err := os.Getwd(); err != nil {
- fmsg.Fatalf("cannot get current directory: %v", err)
+ log.Fatalf("cannot get current directory: %v", err)
} else {
pkgPath = path.Join(dir, pkgPath)
}
@@ -54,7 +56,7 @@ func actionInstall(args []string) {
var workDir string
if p, err := os.MkdirTemp("", "fpkg.*"); err != nil {
- fmsg.Fatalf("cannot create temporary directory: %v", err)
+ log.Fatalf("cannot create temporary directory: %v", err)
} else {
workDir = p
}
@@ -78,19 +80,17 @@ func actionInstall(args []string) {
if s, err := os.Stat(pathSet.metaPath); err != nil {
if !os.IsNotExist(err) {
cleanup()
- fmsg.Fatalf("cannot access %q: %v", pathSet.metaPath, err)
- panic("unreachable")
+ log.Fatalf("cannot access %q: %v", pathSet.metaPath, err)
}
// did not modify app, clean installation condition met later
} else if s.IsDir() {
cleanup()
- fmsg.Fatalf("metadata path %q is not a file", pathSet.metaPath)
- panic("unreachable")
+ log.Fatalf("metadata path %q is not a file", pathSet.metaPath)
} else {
app = loadBundleInfo(pathSet.metaPath, cleanup)
if app.ID != bundle.ID {
cleanup()
- fmsg.Fatalf("app %q claims to have identifier %q", bundle.ID, app.ID)
+ log.Fatalf("app %q claims to have identifier %q", bundle.ID, app.ID)
}
// sec: should verify credentials
}
@@ -102,21 +102,20 @@ func actionInstall(args []string) {
app.Launcher == bundle.Launcher &&
app.ActivationPackage == bundle.ActivationPackage {
cleanup()
- fmsg.Printf("package %q is identical to local application %q", pkgPath, app.ID)
- fmsg.Exit(0)
+ log.Printf("package %q is identical to local application %q", pkgPath, app.ID)
+ internal.Exit(0)
}
// AppID determines uid
if app.AppID != bundle.AppID {
cleanup()
- fmsg.Fatalf("package %q app id %d differs from installed %d", pkgPath, bundle.AppID, app.AppID)
- panic("unreachable")
+ log.Fatalf("package %q app id %d differs from installed %d", pkgPath, bundle.AppID, app.AppID)
}
// sec: should compare version string
- fmsg.VPrintf("installing application %q version %q over local %q", bundle.ID, bundle.Version, app.Version)
+ fmsg.Verbosef("installing application %q version %q over local %q", bundle.ID, bundle.Version, app.Version)
} else {
- fmsg.VPrintf("application %q clean installation", bundle.ID)
+ fmsg.Verbosef("application %q clean installation", bundle.ID)
// sec: should install credentials
}
@@ -174,21 +173,18 @@ func actionInstall(args []string) {
// serialise metadata to ensure consistency
if f, err := os.OpenFile(pathSet.metaPath+"~", os.O_CREATE|os.O_WRONLY|os.O_TRUNC, 0644); err != nil {
cleanup()
- fmsg.Fatalf("cannot create metadata file: %v", err)
- panic("unreachable")
+ log.Fatalf("cannot create metadata file: %v", err)
} else if err = json.NewEncoder(f).Encode(bundle); err != nil {
cleanup()
- fmsg.Fatalf("cannot write metadata: %v", err)
- panic("unreachable")
+ log.Fatalf("cannot write metadata: %v", err)
} else if err = f.Close(); err != nil {
- fmsg.Printf("cannot close metadata file: %v", err)
+ log.Printf("cannot close metadata file: %v", err)
// not fatal
}
if err := os.Rename(pathSet.metaPath+"~", pathSet.metaPath); err != nil {
cleanup()
- fmsg.Fatalf("cannot rename metadata file: %v", err)
- panic("unreachable")
+ log.Fatalf("cannot rename metadata file: %v", err)
}
cleanup()
diff --git a/cmd/fpkg/main.go b/cmd/fpkg/main.go
index f348cb5e..e95a36cb 100644
--- a/cmd/fpkg/main.go
+++ b/cmd/fpkg/main.go
@@ -2,8 +2,10 @@ package main
import (
"flag"
+ "log"
"os"
+ "git.gensokyo.uk/security/fortify/internal"
"git.gensokyo.uk/security/fortify/internal/fmsg"
)
@@ -11,7 +13,7 @@ const shell = "/run/current-system/sw/bin/bash"
func init() {
if err := os.Setenv("SHELL", shell); err != nil {
- fmsg.Fatalf("cannot set $SHELL: %v", err)
+ log.Fatalf("cannot set $SHELL: %v", err)
}
}
@@ -24,14 +26,14 @@ func init() {
}
func main() {
- fmsg.SetPrefix("fpkg")
+ fmsg.Prepare("fpkg")
flag.Parse()
- fmsg.SetVerbose(flagVerbose)
+ fmsg.Store(flagVerbose)
args := flag.Args()
if len(args) < 1 {
- fmsg.Fatal("invalid argument")
+ log.Fatal("invalid argument")
}
switch args[0] {
@@ -41,8 +43,8 @@ func main() {
actionStart(args[1:])
default:
- fmsg.Fatal("invalid argument")
+ log.Fatal("invalid argument")
}
- fmsg.Exit(0)
+ internal.Exit(0)
}
diff --git a/cmd/fpkg/paths.go b/cmd/fpkg/paths.go
index cf36c096..231388e5 100644
--- a/cmd/fpkg/paths.go
+++ b/cmd/fpkg/paths.go
@@ -1,6 +1,7 @@
package main
import (
+ "log"
"os"
"os/exec"
"path"
@@ -25,8 +26,8 @@ func init() {
func lookPath(file string) string {
if p, err := exec.LookPath(file); err != nil {
- fmsg.Fatalf("%s: command not found", file)
- panic("unreachable")
+ log.Fatalf("%s: command not found", file)
+ return ""
} else {
return p
}
@@ -35,15 +36,14 @@ func lookPath(file string) string {
var beforeRunFail = new(atomic.Pointer[func()])
func mustRun(name string, arg ...string) {
- fmsg.VPrintf("spawning process: %q %q", name, arg)
+ fmsg.Verbosef("spawning process: %q %q", name, arg)
cmd := exec.Command(name, arg...)
cmd.Stdin, cmd.Stdout, cmd.Stderr = os.Stdin, os.Stdout, os.Stderr
if err := cmd.Run(); err != nil {
if f := beforeRunFail.Swap(nil); f != nil {
(*f)()
}
- fmsg.Fatalf("%s: %v", name, err)
- panic("unreachable")
+ log.Fatalf("%s: %v", name, err)
}
}
diff --git a/cmd/fpkg/proc.go b/cmd/fpkg/proc.go
index 7fa6df5a..4413496a 100644
--- a/cmd/fpkg/proc.go
+++ b/cmd/fpkg/proc.go
@@ -4,6 +4,7 @@ import (
"encoding/json"
"errors"
"io"
+ "log"
"os"
"os/exec"
@@ -25,14 +26,12 @@ func fortifyApp(config *fst.Config, beforeFail func()) {
)
if p, ok := internal.Path(Fmain); !ok {
beforeFail()
- fmsg.Fatal("invalid fortify path, this copy of fpkg is not compiled correctly")
- panic("unreachable")
+ log.Fatal("invalid fortify path, this copy of fpkg is not compiled correctly")
} else if r, w, err := os.Pipe(); err != nil {
beforeFail()
- fmsg.Fatalf("cannot pipe: %v", err)
- panic("unreachable")
+ log.Fatalf("cannot pipe: %v", err)
} else {
- if fmsg.Verbose() {
+ if fmsg.Load() {
cmd = exec.Command(p, "-v", "app", "3")
} else {
cmd = exec.Command(p, "app", "3")
@@ -45,26 +44,22 @@ func fortifyApp(config *fst.Config, beforeFail func()) {
go func() {
if err := json.NewEncoder(st).Encode(config); err != nil {
beforeFail()
- fmsg.Fatalf("cannot send configuration: %v", err)
- panic("unreachable")
+ log.Fatalf("cannot send configuration: %v", err)
}
}()
if err := cmd.Start(); err != nil {
beforeFail()
- fmsg.Fatalf("cannot start fortify: %v", err)
- panic("unreachable")
+ log.Fatalf("cannot start fortify: %v", err)
}
if err := cmd.Wait(); err != nil {
var exitError *exec.ExitError
if errors.As(err, &exitError) {
beforeFail()
- fmsg.Exit(exitError.ExitCode())
- panic("unreachable")
+ internal.Exit(exitError.ExitCode())
} else {
beforeFail()
- fmsg.Fatalf("cannot wait: %v", err)
- panic("unreachable")
+ log.Fatalf("cannot wait: %v", err)
}
}
}
diff --git a/cmd/fpkg/start.go b/cmd/fpkg/start.go
index 4a882110..71e00281 100644
--- a/cmd/fpkg/start.go
+++ b/cmd/fpkg/start.go
@@ -2,11 +2,12 @@ package main
import (
"flag"
+ "log"
"path"
"git.gensokyo.uk/security/fortify/fst"
"git.gensokyo.uk/security/fortify/helper/bwrap"
- "git.gensokyo.uk/security/fortify/internal/fmsg"
+ "git.gensokyo.uk/security/fortify/internal"
)
func actionStart(args []string) {
@@ -26,7 +27,7 @@ func actionStart(args []string) {
args = set.Args()
if len(args) < 1 {
- fmsg.Fatal("invalid argument")
+ log.Fatal("invalid argument")
}
/*
@@ -37,7 +38,7 @@ func actionStart(args []string) {
pathSet := pathSetByApp(id)
app := loadBundleInfo(pathSet.metaPath, func() {})
if app.ID != id {
- fmsg.Fatalf("app %q claims to have identifier %q", id, app.ID)
+ log.Fatalf("app %q claims to have identifier %q", id, app.ID)
}
/*
@@ -144,7 +145,7 @@ func actionStart(args []string) {
*/
fortifyApp(config, func() {})
- fmsg.Exit(0)
+ internal.Exit(0)
}
func appendGPUFilesystem(config *fst.Config) {
diff --git a/cmd/fpkg/with.go b/cmd/fpkg/with.go
index 03718dd0..6f5b225e 100644
--- a/cmd/fpkg/with.go
+++ b/cmd/fpkg/with.go
@@ -6,7 +6,7 @@ import (
"git.gensokyo.uk/security/fortify/fst"
"git.gensokyo.uk/security/fortify/helper/bwrap"
- "git.gensokyo.uk/security/fortify/internal/fmsg"
+ "git.gensokyo.uk/security/fortify/internal"
)
func withNixDaemon(
@@ -95,7 +95,7 @@ func fortifyAppDropShell(config *fst.Config, dropShell bool, beforeFail func())
config.Command = []string{shell, "-l"}
fortifyApp(config, beforeFail)
beforeFail()
- fmsg.Exit(0)
+ internal.Exit(0)
}
fortifyApp(config, beforeFail)
}
diff --git a/error.go b/error.go
index 7e55874a..b3d19337 100644
--- a/error.go
+++ b/error.go
@@ -2,6 +2,7 @@ package main
import (
"errors"
+ "log"
"git.gensokyo.uk/security/fortify/internal/app"
"git.gensokyo.uk/security/fortify/internal/fmsg"
@@ -10,13 +11,13 @@ import (
func logWaitError(err error) {
var e *fmsg.BaseError
if !fmsg.AsBaseError(err, &e) {
- fmsg.Println("wait failed:", err)
+ 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
- fmsg.Print(e.Message())
+ log.Print(e.Message())
} else {
// inner error are either unwrapped store errors
// or joined errors returned by *appSealTx revert
@@ -24,7 +25,7 @@ func logWaitError(err error) {
var ej app.RevertCompoundError
if !errors.As(se.InnerErr, &ej) {
// does not require special handling
- fmsg.Print(e.Message())
+ log.Print(e.Message())
} else {
errs := ej.Unwrap()
@@ -33,10 +34,10 @@ func logWaitError(err error) {
var eb *fmsg.BaseError
if !errors.As(ei, &eb) {
// unreachable
- fmsg.Println("invalid error type returned by revert:", ei)
+ log.Println("invalid error type returned by revert:", ei)
} else {
// print inner *app.BaseError message
- fmsg.Print(eb.Message())
+ log.Print(eb.Message())
}
}
}
@@ -48,8 +49,8 @@ func logBaseError(err error, message string) {
var e *fmsg.BaseError
if fmsg.AsBaseError(err, &e) {
- fmsg.Print(e.Message())
+ log.Print(e.Message())
} else {
- fmsg.Println(message, err)
+ log.Println(message, err)
}
}
diff --git a/fst/sandbox.go b/fst/sandbox.go
index 0c3918a9..a6b1eb56 100644
--- a/fst/sandbox.go
+++ b/fst/sandbox.go
@@ -53,7 +53,7 @@ func (s *SandboxConfig) Bwrap(os linux.System) (*bwrap.Config, error) {
}
if s.Syscall == nil {
- fmsg.VPrintln("syscall filter not configured, PROCEED WITH CAUTION")
+ fmsg.Verbose("syscall filter not configured, PROCEED WITH CAUTION")
}
var uid int
@@ -121,11 +121,11 @@ func (s *SandboxConfig) Bwrap(os linux.System) (*bwrap.Config, error) {
// get parent dir of socket
dir := path.Dir(pair[1])
if dir == "." || dir == "/" {
- fmsg.VPrintf("dbus socket %q is in an unusual location", pair[1])
+ fmsg.Verbosef("dbus socket %q is in an unusual location", pair[1])
}
hidePaths = append(hidePaths, dir)
} else {
- fmsg.VPrintf("dbus socket %q is not absolute", pair[1])
+ fmsg.Verbosef("dbus socket %q is not absolute", pair[1])
}
}
}
@@ -169,7 +169,7 @@ func (s *SandboxConfig) Bwrap(os linux.System) (*bwrap.Config, error) {
return nil, err
} else if ok {
hidePathMatch[i] = true
- fmsg.VPrintf("hiding paths from %q", c.Src)
+ fmsg.Verbosef("hiding paths from %q", c.Src)
}
}
@@ -221,7 +221,7 @@ func evalSymlinks(os linux.System, v *string) error {
if !errors.Is(err, fs.ErrNotExist) {
return err
}
- fmsg.VPrintf("path %q does not yet exist", *v)
+ fmsg.Verbosef("path %q does not yet exist", *v)
} else {
*v = p
}
diff --git a/helper/bwrap/config_test.go b/helper/bwrap/config_test.go
index ca6e9636..d48f4f4c 100644
--- a/helper/bwrap/config_test.go
+++ b/helper/bwrap/config_test.go
@@ -1,6 +1,7 @@
package bwrap_test
import (
+ "log"
"os"
"slices"
"testing"
@@ -8,11 +9,10 @@ import (
"git.gensokyo.uk/security/fortify/helper/bwrap"
"git.gensokyo.uk/security/fortify/helper/proc"
"git.gensokyo.uk/security/fortify/helper/seccomp"
- "git.gensokyo.uk/security/fortify/internal/fmsg"
)
func TestConfig_Args(t *testing.T) {
- seccomp.CPrintln = fmsg.Println
+ seccomp.CPrintln = log.Println
t.Cleanup(func() { seccomp.CPrintln = nil })
testCases := []struct {
diff --git a/helper/seccomp/export_test.go b/helper/seccomp/export_test.go
index 8e21fe1f..40f81c7a 100644
--- a/helper/seccomp/export_test.go
+++ b/helper/seccomp/export_test.go
@@ -4,12 +4,12 @@ import (
"crypto/sha512"
"errors"
"io"
+ "log"
"slices"
"syscall"
"testing"
"git.gensokyo.uk/security/fortify/helper/seccomp"
- "git.gensokyo.uk/security/fortify/internal/fmsg"
)
func TestExport(t *testing.T) {
@@ -79,7 +79,7 @@ func TestExport(t *testing.T) {
buf := make([]byte, 8)
for _, tc := range testCases {
t.Run(tc.name, func(t *testing.T) {
- seccomp.CPrintln = fmsg.Println
+ seccomp.CPrintln = log.Println
t.Cleanup(func() { seccomp.CPrintln = nil })
e := seccomp.New(tc.opts)
diff --git a/helper/stub.go b/helper/stub.go
index 58913022..12daa9fd 100644
--- a/helper/stub.go
+++ b/helper/stub.go
@@ -14,7 +14,7 @@ import (
"git.gensokyo.uk/security/fortify/helper/bwrap"
"git.gensokyo.uk/security/fortify/helper/proc"
- "git.gensokyo.uk/security/fortify/internal/fmsg"
+ "git.gensokyo.uk/security/fortify/internal"
)
// InternalChildStub is an internal function but exported because it is cross-package;
@@ -40,7 +40,7 @@ func InternalChildStub() {
genericStub(flagRestoreFiles(4, ap, sp))
}
- fmsg.Exit(0)
+ internal.Exit(0)
}
// InternalReplaceExecCommand is an internal function but exported because it is cross-package;
diff --git a/internal/app/init/early.go b/internal/app/init/early.go
index cc1c2f7e..ac2fedbf 100644
--- a/internal/app/init/early.go
+++ b/internal/app/init/early.go
@@ -4,7 +4,7 @@ import (
"os"
"path"
- "git.gensokyo.uk/security/fortify/internal/fmsg"
+ "git.gensokyo.uk/security/fortify/internal"
)
// used by the parent process
@@ -13,6 +13,6 @@ import (
func TryArgv0() {
if len(os.Args) > 0 && path.Base(os.Args[0]) == "init" {
Main()
- fmsg.Exit(0)
+ internal.Exit(0)
}
}
diff --git a/internal/app/init/main.go b/internal/app/init/main.go
index 4c69312e..bf9ecbae 100644
--- a/internal/app/init/main.go
+++ b/internal/app/init/main.go
@@ -2,6 +2,7 @@ package init0
import (
"errors"
+ "log"
"os"
"os/exec"
"os/signal"
@@ -24,17 +25,15 @@ const (
func Main() {
// sharing stdout with shim
// USE WITH CAUTION
- fmsg.SetPrefix("init")
+ fmsg.Prepare("init")
// setting this prevents ptrace
if err := internal.PR_SET_DUMPABLE__SUID_DUMP_DISABLE(); err != nil {
- fmsg.Fatalf("cannot set SUID_DUMP_DISABLE: %s", err)
- panic("unreachable")
+ log.Fatalf("cannot set SUID_DUMP_DISABLE: %s", err)
}
if os.Getpid() != 1 {
- fmsg.Fatal("this process must run as pid 1")
- panic("unreachable")
+ log.Fatal("this process must run as pid 1")
}
// receive setup payload
@@ -44,30 +43,29 @@ func Main() {
)
if f, err := proc.Receive(Env, &payload); err != nil {
if errors.Is(err, proc.ErrInvalid) {
- fmsg.Fatal("invalid config descriptor")
+ log.Fatal("invalid config descriptor")
}
if errors.Is(err, proc.ErrNotSet) {
- fmsg.Fatal("FORTIFY_INIT not set")
+ log.Fatal("FORTIFY_INIT not set")
}
- fmsg.Fatalf("cannot decode init setup payload: %v", err)
- panic("unreachable")
+ log.Fatalf("cannot decode init setup payload: %v", err)
} else {
- fmsg.SetVerbose(payload.Verbose)
+ fmsg.Store(payload.Verbose)
closeSetup = f
// child does not need to see this
if err = os.Unsetenv(Env); err != nil {
- fmsg.Printf("cannot unset %s: %v", Env, err)
+ log.Printf("cannot unset %s: %v", Env, err)
// not fatal
} else {
- fmsg.VPrintln("received configuration")
+ fmsg.Verbose("received configuration")
}
}
// die with parent
if err := internal.PR_SET_PDEATHSIG__SIGKILL(); err != nil {
- fmsg.Fatalf("prctl(PR_SET_PDEATHSIG, SIGKILL): %v", err)
+ log.Fatalf("prctl(PR_SET_PDEATHSIG, SIGKILL): %v", err)
}
cmd := exec.Command(payload.Argv0)
@@ -76,13 +74,13 @@ func Main() {
cmd.Env = os.Environ()
if err := cmd.Start(); err != nil {
- fmsg.Fatalf("cannot start %q: %v", payload.Argv0, err)
+ log.Fatalf("cannot start %q: %v", payload.Argv0, err)
}
fmsg.Suspend()
// close setup pipe as setup is now complete
if err := closeSetup(); err != nil {
- fmsg.Println("cannot close setup pipe:", err)
+ log.Println("cannot close setup pipe:", err)
// not fatal
}
@@ -119,7 +117,7 @@ func Main() {
}
}
if !errors.Is(err, syscall.ECHILD) {
- fmsg.Println("unexpected wait4 response:", err)
+ log.Println("unexpected wait4 response:", err)
}
close(done)
@@ -132,9 +130,12 @@ func Main() {
for {
select {
case s := <-sig:
- fmsg.VPrintln("received", s.String())
- fmsg.Resume() // output could still be withheld at this point, so resume is called
- fmsg.Exit(0)
+ if fmsg.Resume() {
+ fmsg.Verbosef("terminating on %s after process start", s.String())
+ } else {
+ fmsg.Verbosef("terminating on %s", s.String())
+ }
+ internal.Exit(0)
case w := <-info:
if w.wpid == cmd.Process.Pid {
// initial process exited, output is most likely available again
@@ -155,10 +156,10 @@ func Main() {
}()
}
case <-done:
- fmsg.Exit(r)
+ internal.Exit(r)
case <-timeout:
- fmsg.Println("timeout exceeded waiting for lingering processes")
- fmsg.Exit(r)
+ log.Println("timeout exceeded waiting for lingering processes")
+ internal.Exit(r)
}
}
}
diff --git a/internal/app/seal.go b/internal/app/seal.go
index c78add93..fb3b3ce2 100644
--- a/internal/app/seal.go
+++ b/internal/app/seal.go
@@ -191,7 +191,7 @@ func (a *app) Seal(config *fst.Config) error {
// map sandbox config to bwrap
if config.Confinement.Sandbox == nil {
- fmsg.VPrintln("sandbox configuration not supplied, PROCEED WITH CAUTION")
+ fmsg.Verbose("sandbox configuration not supplied, PROCEED WITH CAUTION")
// permissive defaults
conf := &fst.SandboxConfig{
@@ -264,7 +264,7 @@ func (a *app) Seal(config *fst.Config) error {
}
// verbose log seal information
- fmsg.VPrintf("created application seal for uid %s (%s) groups: %v, command: %s",
+ fmsg.Verbosef("created application seal for uid %s (%s) groups: %v, command: %s",
seal.sys.user.us, seal.sys.user.username, config.Confinement.Groups, config.Command)
// seal app and release lock
diff --git a/internal/app/share.go b/internal/app/share.go
index 9e7d0f17..c7f0c7a3 100644
--- a/internal/app/share.go
+++ b/internal/app/share.go
@@ -143,7 +143,7 @@ func (seal *appSeal) setupShares(bus [2]*dbus.Config, os linux.System) error {
if seal.et.Has(system.EWayland) {
var socketPath string
if name, ok := os.LookupEnv(wl.WaylandDisplay); !ok {
- fmsg.VPrintln(wl.WaylandDisplay + " is not set, assuming " + wl.FallbackName)
+ fmsg.Verbose(wl.WaylandDisplay + " is not set, assuming " + wl.FallbackName)
socketPath = path.Join(seal.RuntimePath, wl.FallbackName)
} else if !path.IsAbs(name) {
socketPath = path.Join(seal.RuntimePath, name)
@@ -166,7 +166,7 @@ func (seal *appSeal) setupShares(bus [2]*dbus.Config, os linux.System) error {
seal.sys.Wayland(outerPath, socketPath, appID, seal.id)
seal.sys.bwrap.Bind(outerPath, innerPath)
} else { // bind mount wayland socket (insecure)
- fmsg.VPrintln("direct wayland access, PROCEED WITH CAUTION")
+ fmsg.Verbose("direct wayland access, PROCEED WITH CAUTION")
seal.sys.bwrap.Bind(socketPath, innerPath)
// ensure Wayland socket ACL (e.g. `/run/user/%d/wayland-%d`)
@@ -229,7 +229,7 @@ func (seal *appSeal) setupShares(bus [2]*dbus.Config, os linux.System) error {
// publish current user's pulse cookie for target user
if src, err := discoverPulseCookie(os); err != nil {
// not fatal
- fmsg.VPrintln(strings.TrimSpace(err.(*fmsg.BaseError).Message()))
+ fmsg.Verbose(strings.TrimSpace(err.(*fmsg.BaseError).Message()))
} else {
dst := path.Join(seal.share, "pulse-cookie")
innerDst := fst.Tmp + "/pulse-cookie"
diff --git a/internal/app/shim/main.go b/internal/app/shim/main.go
index 39b7d4f9..7616945f 100644
--- a/internal/app/shim/main.go
+++ b/internal/app/shim/main.go
@@ -3,6 +3,7 @@ package shim
import (
"context"
"errors"
+ "log"
"os"
"os/exec"
"os/signal"
@@ -25,12 +26,11 @@ import (
func Main() {
// sharing stdout with fortify
// USE WITH CAUTION
- fmsg.SetPrefix("shim")
+ fmsg.Prepare("shim")
// setting this prevents ptrace
if err := internal.PR_SET_DUMPABLE__SUID_DUMP_DISABLE(); err != nil {
- fmsg.Fatalf("cannot set SUID_DUMP_DISABLE: %s", err)
- panic("unreachable")
+ log.Fatalf("cannot set SUID_DUMP_DISABLE: %s", err)
}
// receive setup payload
@@ -40,21 +40,20 @@ func Main() {
)
if f, err := proc.Receive(Env, &payload); err != nil {
if errors.Is(err, proc.ErrInvalid) {
- fmsg.Fatal("invalid config descriptor")
+ log.Fatal("invalid config descriptor")
}
if errors.Is(err, proc.ErrNotSet) {
- fmsg.Fatal("FORTIFY_SHIM not set")
+ log.Fatal("FORTIFY_SHIM not set")
}
- fmsg.Fatalf("cannot decode shim setup payload: %v", err)
- panic("unreachable")
+ log.Fatalf("cannot decode shim setup payload: %v", err)
} else {
- fmsg.SetVerbose(payload.Verbose)
+ fmsg.Store(payload.Verbose)
closeSetup = f
}
if payload.Bwrap == nil {
- fmsg.Fatal("bwrap config not supplied")
+ log.Fatal("bwrap config not supplied")
}
// restore bwrap sync fd
@@ -65,7 +64,7 @@ func Main() {
// close setup socket
if err := closeSetup(); err != nil {
- fmsg.Println("cannot close setup pipe:", err)
+ log.Println("cannot close setup pipe:", err)
// not fatal
}
@@ -73,15 +72,15 @@ func Main() {
if s, err := os.Stat(payload.Home); err != nil {
if os.IsNotExist(err) {
if err = os.Mkdir(payload.Home, 0700); err != nil {
- fmsg.Fatalf("cannot create home directory: %v", err)
+ log.Fatalf("cannot create home directory: %v", err)
}
} else {
- fmsg.Fatalf("cannot access home directory: %v", err)
+ log.Fatalf("cannot access home directory: %v", err)
}
// home directory is created, proceed
} else if !s.IsDir() {
- fmsg.Fatalf("data path %q is not a directory", payload.Home)
+ log.Fatalf("data path %q is not a directory", payload.Home)
}
var ic init0.Payload
@@ -95,10 +94,10 @@ func Main() {
// no argv, look up shell instead
var ok bool
if payload.Bwrap.SetEnv == nil {
- fmsg.Fatal("no command was specified and environment is unset")
+ log.Fatal("no command was specified and environment is unset")
}
if ic.Argv0, ok = payload.Bwrap.SetEnv["SHELL"]; !ok {
- fmsg.Fatal("no command was specified and $SHELL was unset")
+ log.Fatal("no command was specified and $SHELL was unset")
}
ic.Argv = []string{ic.Argv0}
@@ -110,20 +109,20 @@ func Main() {
// serve setup payload
if fd, encoder, err := proc.Setup(&extraFiles); err != nil {
- fmsg.Fatalf("cannot pipe: %v", err)
+ log.Fatalf("cannot pipe: %v", err)
} else {
conf.SetEnv[init0.Env] = strconv.Itoa(fd)
go func() {
- fmsg.VPrintln("transmitting config to init")
+ fmsg.Verbose("transmitting config to init")
if err = encoder.Encode(&ic); err != nil {
- fmsg.Fatalf("cannot transmit init config: %v", err)
+ log.Fatalf("cannot transmit init config: %v", err)
}
}()
}
helper.BubblewrapName = payload.Exec[0] // resolved bwrap path by parent
- if fmsg.Verbose() {
- seccomp.CPrintln = fmsg.Println
+ if fmsg.Load() {
+ seccomp.CPrintln = log.Println
}
if b, err := helper.NewBwrap(
conf, path.Join(fst.Tmp, "sbin/init"),
@@ -131,7 +130,7 @@ func Main() {
extraFiles,
syncFd,
); err != nil {
- fmsg.Fatalf("malformed sandbox config: %v", err)
+ log.Fatalf("malformed sandbox config: %v", err)
} else {
b.Stdin(os.Stdin).Stdout(os.Stdout).Stderr(os.Stderr)
ctx, stop := signal.NotifyContext(context.Background(), os.Interrupt, syscall.SIGTERM)
@@ -139,15 +138,15 @@ func Main() {
// run and pass through exit code
if err = b.Start(ctx, false); err != nil {
- fmsg.Fatalf("cannot start target process: %v", err)
+ log.Fatalf("cannot start target process: %v", err)
} else if err = b.Wait(); err != nil {
var exitError *exec.ExitError
if !errors.As(err, &exitError) {
- fmsg.Println("wait:", err)
- fmsg.Exit(127)
+ log.Printf("wait: %v", err)
+ internal.Exit(127)
panic("unreachable")
}
- fmsg.Exit(exitError.ExitCode())
+ internal.Exit(exitError.ExitCode())
panic("unreachable")
}
}
diff --git a/internal/app/shim/manager.go b/internal/app/shim/manager.go
index 106e4865..c4605635 100644
--- a/internal/app/shim/manager.go
+++ b/internal/app/shim/manager.go
@@ -4,6 +4,7 @@ import (
"context"
"encoding/gob"
"errors"
+ "log"
"os"
"os/exec"
"strconv"
@@ -54,8 +55,7 @@ func (s *Shim) Start(
// prepare user switcher invocation
var fsu string
if p, ok := internal.Path(internal.Fsu); !ok {
- fmsg.Fatal("invalid fsu path, this copy of fortify is not compiled correctly")
- panic("unreachable")
+ log.Fatal("invalid fsu path, this copy of fortify is not compiled correctly")
} else {
fsu = p
}
@@ -75,7 +75,7 @@ func (s *Shim) Start(
// format fsu supplementary groups
if len(supp) > 0 {
- fmsg.VPrintf("attaching supplementary group ids %s", supp)
+ fmsg.Verbosef("attaching supplementary group ids %s", supp)
s.cmd.Env = append(s.cmd.Env, "FORTIFY_GROUPS="+strings.Join(supp, " "))
}
s.cmd.Stdin, s.cmd.Stdout, s.cmd.Stderr = os.Stdin, os.Stdout, os.Stderr
@@ -87,7 +87,7 @@ func (s *Shim) Start(
s.sync = &fd
}
- fmsg.VPrintln("starting shim via fsu:", s.cmd)
+ fmsg.Verbose("starting shim via fsu:", s.cmd)
// withhold messages to stderr
fmsg.Suspend()
if err := s.cmd.Start(); err != nil {
diff --git a/internal/app/start.go b/internal/app/start.go
index 171e707e..467735e1 100644
--- a/internal/app/start.go
+++ b/internal/app/start.go
@@ -4,6 +4,7 @@ import (
"context"
"errors"
"fmt"
+ "log"
"os/exec"
"path/filepath"
"strings"
@@ -81,7 +82,7 @@ func (a *app) Run(ctx context.Context, rs *RunState) error {
Bwrap: a.seal.sys.bwrap,
Home: a.seal.sys.user.data,
- Verbose: fmsg.Verbose(),
+ Verbose: fmsg.Load(),
}); err != nil {
return err
}
@@ -119,8 +120,8 @@ func (a *app) Run(ctx context.Context, rs *RunState) error {
} else {
rs.ExitCode = a.shim.Unwrap().ProcessState.ExitCode()
}
- if fmsg.Verbose() {
- fmsg.VPrintf("process %d exited with exit code %d", a.shim.Unwrap().Process.Pid, rs.ExitCode)
+ if fmsg.Load() {
+ fmsg.Verbosef("process %d exited with exit code %d", a.shim.Unwrap().Process.Pid, rs.ExitCode)
}
// this is reached when a fault makes an already running shim impossible to continue execution
@@ -128,11 +129,11 @@ func (a *app) Run(ctx context.Context, rs *RunState) error {
// the effects of this is similar to the alternative exit path and ensures shim death
case err := <-a.shim.WaitFallback():
rs.ExitCode = 255
- fmsg.Printf("cannot terminate shim on faulted setup: %v", err)
+ log.Printf("cannot terminate shim on faulted setup: %v", err)
// alternative exit path relying on shim behaviour on monitor process exit
case <-ctx.Done():
- fmsg.VPrintln("alternative exit path selected")
+ fmsg.Verbose("alternative exit path selected")
}
// child process exited, resume output
@@ -163,10 +164,10 @@ func (a *app) Run(ctx context.Context, rs *RunState) error {
} else {
if l := len(states); l == 0 {
// cleanup globals as the final launcher
- fmsg.VPrintln("no other launchers active, will clean up globals")
+ fmsg.Verbose("no other launchers active, will clean up globals")
ec.Set(system.User)
} else {
- fmsg.VPrintf("found %d active launchers, cleaning up without globals", l)
+ fmsg.Verbosef("found %d active launchers, cleaning up without globals", l)
}
// accumulate capabilities of other launchers
@@ -174,7 +175,7 @@ func (a *app) Run(ctx context.Context, rs *RunState) error {
if s.Config != nil {
*rt |= s.Config.Confinement.Enablements
} else {
- fmsg.Printf("state entry %d does not contain config", i)
+ log.Printf("state entry %d does not contain config", i)
}
}
}
@@ -184,7 +185,7 @@ func (a *app) Run(ctx context.Context, rs *RunState) error {
ec.Set(i)
}
}
- if fmsg.Verbose() {
+ if fmsg.Load() {
labels := make([]string, 0, system.ELen+1)
for i := system.Enablement(0); i < system.Enablement(system.ELen+2); i++ {
if ec.Has(i) {
@@ -192,7 +193,7 @@ func (a *app) Run(ctx context.Context, rs *RunState) error {
}
}
if len(labels) > 0 {
- fmsg.VPrintln("reverting operations labelled", strings.Join(labels, ", "))
+ fmsg.Verbose("reverting operations labelled", strings.Join(labels, ", "))
}
}
diff --git a/helper/proc/self.go b/internal/executable.go
index 6dc92eb7..86ffab96 100644
--- a/helper/proc/self.go
+++ b/internal/executable.go
@@ -1,10 +1,9 @@
-package proc
+package internal
import (
+ "log"
"os"
"sync"
-
- "git.gensokyo.uk/security/fortify/internal/fmsg"
)
var (
@@ -14,7 +13,7 @@ var (
func copyExecutable() {
if name, err := os.Executable(); err != nil {
- fmsg.Fatalf("cannot read executable path: %v", err)
+ log.Fatalf("cannot read executable path: %v", err)
} else {
executable = name
}
diff --git a/internal/exit.go b/internal/exit.go
new file mode 100644
index 00000000..67819436
--- /dev/null
+++ b/internal/exit.go
@@ -0,0 +1,9 @@
+package internal
+
+import (
+ "os"
+
+ "git.gensokyo.uk/security/fortify/internal/fmsg"
+)
+
+func Exit(code int) { fmsg.BeforeExit(); os.Exit(code) }
diff --git a/internal/fmsg/defer.go b/internal/fmsg/defer.go
deleted file mode 100644
index 677f5ceb..00000000
--- a/internal/fmsg/defer.go
+++ /dev/null
@@ -1,98 +0,0 @@
-package fmsg
-
-import (
- "os"
- "sync"
- "sync/atomic"
-)
-
-var (
- wstate atomic.Bool
- dropped atomic.Uint64
- withhold = make(chan struct{}, 1)
- msgbuf = make(chan dOp, 64) // these ops are tiny so a large buffer is allocated for withholding output
-
- dequeueOnce sync.Once
- queueSync sync.WaitGroup
-)
-
-func dequeue() {
- go func() {
- for {
- select {
- case op := <-msgbuf:
- op.Do()
- queueSync.Done()
- case <-withhold:
- <-withhold
- }
- }
- }()
-}
-
-// queue submits ops to msgbuf but drops messages
-// when the buffer is full and dequeue is withholding
-func queue(op dOp) {
- queueSync.Add(1)
-
- select {
- case msgbuf <- op:
- default:
- // send the op anyway if not withholding
- // as dequeue will get to it eventually
- if !wstate.Load() {
- msgbuf <- op
- } else {
- queueSync.Done()
- // increment dropped message count
- dropped.Add(1)
- }
- }
-}
-
-type dOp interface{ Do() }
-
-func Exit(code int) {
- Resume() // resume here to avoid deadlock
- queueSync.Wait()
- os.Exit(code)
-}
-
-func Suspend() {
- dequeueOnce.Do(dequeue)
- if wstate.CompareAndSwap(false, true) {
- queueSync.Wait()
- withhold <- struct{}{}
- }
-}
-
-func Resume() {
- dequeueOnce.Do(dequeue)
- if wstate.CompareAndSwap(true, false) {
- withhold <- struct{}{}
- if d := dropped.Swap(0); d != 0 {
- Printf("dropped %d messages during withhold", d)
- }
- }
-}
-
-type dPrint []any
-
-func (v dPrint) Do() {
- std.Print(v...)
-}
-
-type dPrintf struct {
- format string
- v []any
-}
-
-func (d *dPrintf) Do() {
- std.Printf(d.format, d.v...)
-}
-
-type dPrintln []any
-
-func (v dPrintln) Do() {
- std.Println(v...)
-}
diff --git a/internal/fmsg/fmsg.go b/internal/fmsg/fmsg.go
index d4027204..48538380 100644
--- a/internal/fmsg/fmsg.go
+++ b/internal/fmsg/fmsg.go
@@ -2,39 +2,85 @@
package fmsg
import (
+ "bytes"
+ "io"
"log"
"os"
+ "sync"
+ "sync/atomic"
+ "syscall"
)
-var std = log.New(os.Stderr, "fortify: ", 0)
+const (
+ bufSize = 4 * 1024
+ bufSizeMax = 16 * 1024 * 1024
+)
-func SetPrefix(prefix string) {
- prefix += ": "
- std.SetPrefix(prefix)
- std.SetPrefix(prefix)
-}
+var o = &suspendable{w: os.Stderr}
+
+// Prepare configures the system logger for [Suspend] and [Resume] to take effect.
+func Prepare(prefix string) { log.SetPrefix(prefix + ": "); log.SetFlags(0); log.SetOutput(o) }
+
+type suspendable struct {
+ w io.Writer
+ s atomic.Bool
-func Print(v ...any) {
- dequeueOnce.Do(dequeue)
- queue(dPrint(v))
+ buf bytes.Buffer
+ bufOnce sync.Once
+ bufMu sync.Mutex
+ dropped int
}
-func Printf(format string, v ...any) {
- dequeueOnce.Do(dequeue)
- queue(&dPrintf{format, v})
+func (s *suspendable) Write(p []byte) (n int, err error) {
+ if !s.s.Load() {
+ return s.w.Write(p)
+ }
+ s.bufOnce.Do(func() { s.prepareBuf() })
+
+ s.bufMu.Lock()
+ defer s.bufMu.Unlock()
+
+ if l := len(p); s.buf.Len()+l > bufSizeMax {
+ s.dropped += l
+ return 0, syscall.ENOMEM
+ }
+ return s.buf.Write(p)
}
-func Println(v ...any) {
- dequeueOnce.Do(dequeue)
- queue(dPrintln(v))
+func (s *suspendable) prepareBuf() { s.buf.Grow(bufSize) }
+func (s *suspendable) Suspend() bool { return o.s.CompareAndSwap(false, true) }
+func (s *suspendable) Resume() (resumed bool, dropped uintptr, n int64, err error) {
+ if o.s.CompareAndSwap(true, false) {
+ o.bufMu.Lock()
+ defer o.bufMu.Unlock()
+
+ resumed = true
+ dropped = uintptr(o.dropped)
+
+ o.dropped = 0
+ n, err = io.Copy(s.w, &s.buf)
+ s.buf = bytes.Buffer{}
+ s.prepareBuf()
+ }
+ return
}
-func Fatal(v ...any) {
- Print(v...)
- Exit(1)
+func Suspend() bool { return o.Suspend() }
+func Resume() bool {
+ resumed, dropped, _, err := o.Resume()
+ if err != nil {
+ // probably going to result in an error as well,
+ // so this call is as good as unreachable
+ log.Printf("cannot dump buffer on resume: %v", err)
+ }
+ if resumed && dropped > 0 {
+ log.Fatalf("dropped %d bytes while output is suspended", dropped)
+ }
+ return resumed
}
-func Fatalf(format string, v ...any) {
- Printf(format, v...)
- Exit(1)
+func BeforeExit() {
+ if Resume() {
+ log.Printf("beforeExit reached on suspended output")
+ }
}
diff --git a/internal/fmsg/verbose.go b/internal/fmsg/verbose.go
index 72a92a69..a8e4c81f 100644
--- a/internal/fmsg/verbose.go
+++ b/internal/fmsg/verbose.go
@@ -1,25 +1,23 @@
package fmsg
-import "sync/atomic"
+import (
+ "log"
+ "sync/atomic"
+)
var verbose = new(atomic.Bool)
-func Verbose() bool {
- return verbose.Load()
-}
-
-func SetVerbose(v bool) {
- verbose.Store(v)
-}
+func Load() bool { return verbose.Load() }
+func Store(v bool) { verbose.Store(v) }
-func VPrintf(format string, v ...any) {
+func Verbosef(format string, v ...any) {
if verbose.Load() {
- Printf(format, v...)
+ log.Printf(format, v...)
}
}
-func VPrintln(v ...any) {
+func Verbose(v ...any) {
if verbose.Load() {
- Println(v...)
+ log.Println(v...)
}
}
diff --git a/internal/linux/interface.go b/internal/linux/interface.go
index 68129363..cf25ecb1 100644
--- a/internal/linux/interface.go
+++ b/internal/linux/interface.go
@@ -54,7 +54,7 @@ type Paths struct {
func CopyPaths(os System, v *Paths) {
v.SharePath = path.Join(os.TempDir(), "fortify."+strconv.Itoa(os.Geteuid()))
- fmsg.VPrintf("process share directory at %q", v.SharePath)
+ fmsg.Verbosef("process share directory at %q", v.SharePath)
if r, ok := os.LookupEnv(xdgRuntimeDir); !ok || r == "" || !path.IsAbs(r) {
// fall back to path in share since fortify has no hard XDG dependency
@@ -65,5 +65,5 @@ func CopyPaths(os System, v *Paths) {
v.RunDirPath = path.Join(v.RuntimePath, "fortify")
}
- fmsg.VPrintf("runtime directory at %q", v.RunDirPath)
+ fmsg.Verbosef("runtime directory at %q", v.RunDirPath)
}
diff --git a/internal/linux/std.go b/internal/linux/std.go
index 1434f1be..4850cf94 100644
--- a/internal/linux/std.go
+++ b/internal/linux/std.go
@@ -3,6 +3,7 @@ package linux
import (
"errors"
"io/fs"
+ "log"
"os"
"os/exec"
"os/user"
@@ -11,9 +12,7 @@ import (
"sync"
"syscall"
- "git.gensokyo.uk/security/fortify/helper/proc"
"git.gensokyo.uk/security/fortify/internal"
- "git.gensokyo.uk/security/fortify/internal/fmsg"
)
// Std implements System using the standard library.
@@ -33,13 +32,13 @@ func (s *Std) Geteuid() int { return os.Geteuid(
func (s *Std) LookupEnv(key string) (string, bool) { return os.LookupEnv(key) }
func (s *Std) TempDir() string { return os.TempDir() }
func (s *Std) LookPath(file string) (string, error) { return exec.LookPath(file) }
-func (s *Std) MustExecutable() string { return proc.MustExecutable() }
+func (s *Std) MustExecutable() string { return internal.MustExecutable() }
func (s *Std) LookupGroup(name string) (*user.Group, error) { return user.LookupGroup(name) }
func (s *Std) ReadDir(name string) ([]os.DirEntry, error) { return os.ReadDir(name) }
func (s *Std) Stat(name string) (fs.FileInfo, error) { return os.Stat(name) }
func (s *Std) Open(name string) (fs.File, error) { return os.Open(name) }
func (s *Std) EvalSymlinks(path string) (string, error) { return filepath.EvalSymlinks(path) }
-func (s *Std) Exit(code int) { fmsg.Exit(code) }
+func (s *Std) Exit(code int) { internal.Exit(code) }
const xdgRuntimeDir = "XDG_RUNTIME_DIR"
@@ -74,8 +73,9 @@ func (s *Std) Uid(aid int) (int, error) {
u.uid = -1
if fsu, ok := internal.Check(internal.Fsu); !ok {
- fmsg.Fatal("invalid fsu path, this copy of fortify is not compiled correctly")
- panic("unreachable")
+ log.Fatal("invalid fsu path, this copy of fortify is not compiled correctly")
+ // unreachable
+ return 0, syscall.EBADE
} else {
cmd := exec.Command(fsu)
cmd.Path = fsu
diff --git a/internal/state/multi.go b/internal/state/multi.go
index bb3764f6..ee43ccf3 100644
--- a/internal/state/multi.go
+++ b/internal/state/multi.go
@@ -85,17 +85,17 @@ func (s *multiStore) List() ([]int, error) {
for _, e := range entries {
// skip non-directories
if !e.IsDir() {
- fmsg.VPrintf("skipped non-directory entry %q", e.Name())
+ fmsg.Verbosef("skipped non-directory entry %q", e.Name())
continue
}
// skip non-numerical names
if v, err := strconv.Atoi(e.Name()); err != nil {
- fmsg.VPrintf("skipped non-aid entry %q", e.Name())
+ fmsg.Verbosef("skipped non-aid entry %q", e.Name())
continue
} else {
if v < 0 || v > 9999 {
- fmsg.VPrintf("skipped out of bounds entry %q", e.Name())
+ fmsg.Verbosef("skipped out of bounds entry %q", e.Name())
continue
}
diff --git a/internal/system/acl.go b/internal/system/acl.go
index 935bee4e..e6e6e370 100644
--- a/internal/system/acl.go
+++ b/internal/system/acl.go
@@ -36,18 +36,18 @@ func (a *ACL) Type() Enablement {
}
func (a *ACL) apply(sys *I) error {
- fmsg.VPrintln("applying ACL", a)
+ fmsg.Verbose("applying ACL", a)
return fmsg.WrapErrorSuffix(acl.UpdatePerm(a.path, sys.uid, a.perms...),
fmt.Sprintf("cannot apply ACL entry to %q:", a.path))
}
func (a *ACL) revert(sys *I, ec *Criteria) error {
if ec.hasType(a) {
- fmsg.VPrintln("stripping ACL", a)
+ fmsg.Verbose("stripping ACL", a)
return fmsg.WrapErrorSuffix(acl.UpdatePerm(a.path, sys.uid),
fmt.Sprintf("cannot strip ACL entry from %q:", a.path))
} else {
- fmsg.VPrintln("skipping ACL", a)
+ fmsg.Verbose("skipping ACL", a)
return nil
}
}
diff --git a/internal/system/dbus.go b/internal/system/dbus.go
index fd995bb0..f52adf15 100644
--- a/internal/system/dbus.go
+++ b/internal/system/dbus.go
@@ -3,6 +3,7 @@ package system
import (
"bytes"
"errors"
+ "log"
"strings"
"sync"
@@ -47,12 +48,12 @@ func (sys *I) ProxyDBus(session, system *dbus.Config, sessionPath, systemPath st
d.proxy = dbus.New(sessionBus, systemBus)
defer func() {
- if fmsg.Verbose() && d.proxy.Sealed() {
- fmsg.VPrintln("sealed session proxy", session.Args(sessionBus))
+ if fmsg.Load() && d.proxy.Sealed() {
+ fmsg.Verbose("sealed session proxy", session.Args(sessionBus))
if system != nil {
- fmsg.VPrintln("sealed system proxy", system.Args(systemBus))
+ fmsg.Verbose("sealed system proxy", system.Args(systemBus))
}
- fmsg.VPrintln("message bus proxy final args:", d.proxy)
+ fmsg.Verbose("message bus proxy final args:", d.proxy)
}
}()
@@ -78,9 +79,9 @@ func (d *DBus) Type() Enablement {
}
func (d *DBus) apply(sys *I) error {
- fmsg.VPrintf("session bus proxy on %q for upstream %q", d.proxy.Session()[1], d.proxy.Session()[0])
+ fmsg.Verbosef("session bus proxy on %q for upstream %q", d.proxy.Session()[1], d.proxy.Session()[0])
if d.system {
- fmsg.VPrintf("system bus proxy on %q for upstream %q", d.proxy.System()[1], d.proxy.System()[0])
+ fmsg.Verbosef("system bus proxy on %q for upstream %q", d.proxy.System()[1], d.proxy.System()[0])
}
// this starts the process and blocks until ready
@@ -89,15 +90,15 @@ func (d *DBus) apply(sys *I) error {
return fmsg.WrapErrorSuffix(err,
"cannot start message bus proxy:")
}
- fmsg.VPrintln("starting message bus proxy:", d.proxy)
+ fmsg.Verbose("starting message bus proxy:", d.proxy)
return nil
}
func (d *DBus) revert(_ *I, _ *Criteria) error {
// criteria ignored here since dbus is always process-scoped
- fmsg.VPrintln("terminating message bus proxy")
+ fmsg.Verbose("terminating message bus proxy")
d.proxy.Close()
- defer fmsg.VPrintln("message bus proxy exit")
+ defer fmsg.Verbose("message bus proxy exit")
return fmsg.WrapErrorSuffix(d.proxy.Wait(), "message bus proxy error:")
}
@@ -144,7 +145,7 @@ func (s *scanToFmsg) write(p []byte, a int) (int, error) {
func (s *scanToFmsg) Dump() {
s.mu.RLock()
for _, msg := range s.msgbuf {
- fmsg.Println(msg)
+ log.Println(msg)
}
s.mu.RUnlock()
}
diff --git a/internal/system/link.go b/internal/system/link.go
index cbde3a1f..7e690c78 100644
--- a/internal/system/link.go
+++ b/internal/system/link.go
@@ -28,18 +28,18 @@ type Hardlink struct {
func (l *Hardlink) Type() Enablement { return l.et }
func (l *Hardlink) apply(_ *I) error {
- fmsg.VPrintln("linking ", l)
+ fmsg.Verbose("linking ", l)
return fmsg.WrapErrorSuffix(os.Link(l.src, l.dst),
fmt.Sprintf("cannot link %q:", l.dst))
}
func (l *Hardlink) revert(_ *I, ec *Criteria) error {
if ec.hasType(l) {
- fmsg.VPrintf("removing hard link %q", l.dst)
+ fmsg.Verbosef("removing hard link %q", l.dst)
return fmsg.WrapErrorSuffix(os.Remove(l.dst),
fmt.Sprintf("cannot remove hard link %q:", l.dst))
} else {
- fmsg.VPrintf("skipping hard link %q", l.dst)
+ fmsg.Verbosef("skipping hard link %q", l.dst)
return nil
}
}
diff --git a/internal/system/mkdir.go b/internal/system/mkdir.go
index b634da45..855b339d 100644
--- a/internal/system/mkdir.go
+++ b/internal/system/mkdir.go
@@ -40,7 +40,7 @@ func (m *Mkdir) Type() Enablement {
}
func (m *Mkdir) apply(_ *I) error {
- fmsg.VPrintln("ensuring directory", m)
+ fmsg.Verbose("ensuring directory", m)
// create directory
err := os.Mkdir(m.path, m.perm)
@@ -61,11 +61,11 @@ func (m *Mkdir) revert(_ *I, ec *Criteria) error {
}
if ec.hasType(m) {
- fmsg.VPrintln("destroying ephemeral directory", m)
+ fmsg.Verbose("destroying ephemeral directory", m)
return fmsg.WrapErrorSuffix(os.Remove(m.path),
fmt.Sprintf("cannot remove ephemeral directory %q:", m.path))
} else {
- fmsg.VPrintln("skipping ephemeral directory", m)
+ fmsg.Verbose("skipping ephemeral directory", m)
return nil
}
}
diff --git a/internal/system/op.go b/internal/system/op.go
index 8a98fa78..08b57946 100644
--- a/internal/system/op.go
+++ b/internal/system/op.go
@@ -3,6 +3,7 @@ package system
import (
"context"
"errors"
+ "log"
"os"
"sync"
@@ -105,9 +106,9 @@ func (sys *I) Commit(ctx context.Context) error {
// sp is set to nil when all ops are applied
if sp != nil {
// rollback partial commit
- fmsg.VPrintf("commit faulted after %d ops, rolling back partial commit", len(sp.ops))
+ fmsg.Verbosef("commit faulted after %d ops, rolling back partial commit", len(sp.ops))
if err := sp.Revert(&Criteria{nil}); err != nil {
- fmsg.Println("errors returned reverting partial commit:", err)
+ log.Println("errors returned reverting partial commit:", err)
}
}
}()
diff --git a/internal/system/tmpfiles.go b/internal/system/tmpfiles.go
index 7dff7c2d..8208e030 100644
--- a/internal/system/tmpfiles.go
+++ b/internal/system/tmpfiles.go
@@ -44,7 +44,7 @@ func (t *Tmpfile) Type() Enablement {
func (t *Tmpfile) apply(_ *I) error {
switch t.method {
case tmpfileCopy:
- fmsg.VPrintln("publishing tmpfile", t)
+ fmsg.Verbose("publishing tmpfile", t)
return fmsg.WrapErrorSuffix(copyFile(t.dst, t.src),
fmt.Sprintf("cannot copy tmpfile %q:", t.dst))
default:
@@ -54,11 +54,11 @@ func (t *Tmpfile) apply(_ *I) error {
func (t *Tmpfile) revert(_ *I, ec *Criteria) error {
if ec.hasType(t) {
- fmsg.VPrintf("removing tmpfile %q", t.dst)
+ fmsg.Verbosef("removing tmpfile %q", t.dst)
return fmsg.WrapErrorSuffix(os.Remove(t.dst),
fmt.Sprintf("cannot remove tmpfile %q:", t.dst))
} else {
- fmsg.VPrintf("skipping tmpfile %q", t.dst)
+ fmsg.Verbosef("skipping tmpfile %q", t.dst)
return nil
}
}
diff --git a/internal/system/wayland.go b/internal/system/wayland.go
index 9646b467..ac3634ae 100644
--- a/internal/system/wayland.go
+++ b/internal/system/wayland.go
@@ -45,7 +45,7 @@ func (w Wayland) apply(sys *I) error {
return fmsg.WrapErrorSuffix(err,
fmt.Sprintf("cannot attach to wayland on %q:", w.pair[1]))
} else {
- fmsg.VPrintf("wayland attached on %q", w.pair[1])
+ fmsg.Verbosef("wayland attached on %q", w.pair[1])
}
if sp, err := w.conn.Bind(w.pair[0], w.appID, w.instanceID); err != nil {
@@ -53,7 +53,7 @@ func (w Wayland) apply(sys *I) error {
fmt.Sprintf("cannot bind to socket on %q:", w.pair[0]))
} else {
sys.sp = sp
- fmsg.VPrintf("wayland listening on %q", w.pair[0])
+ fmsg.Verbosef("wayland listening on %q", w.pair[0])
return fmsg.WrapErrorSuffix(errors.Join(os.Chmod(w.pair[0], 0), acl.UpdatePerm(w.pair[0], sys.uid, acl.Read, acl.Write, acl.Execute)),
fmt.Sprintf("cannot chmod socket on %q:", w.pair[0]))
}
@@ -61,16 +61,16 @@ func (w Wayland) apply(sys *I) error {
func (w Wayland) revert(_ *I, ec *Criteria) error {
if ec.hasType(w) {
- fmsg.VPrintf("removing wayland socket on %q", w.pair[0])
+ fmsg.Verbosef("removing wayland socket on %q", w.pair[0])
if err := os.Remove(w.pair[0]); err != nil && !errors.Is(err, os.ErrNotExist) {
return err
}
- fmsg.VPrintf("detaching from wayland on %q", w.pair[1])
+ fmsg.Verbosef("detaching from wayland on %q", w.pair[1])
return fmsg.WrapErrorSuffix(w.conn.Close(),
fmt.Sprintf("cannot detach from wayland on %q:", w.pair[1]))
} else {
- fmsg.VPrintf("skipping wayland cleanup on %q", w.pair[0])
+ fmsg.Verbosef("skipping wayland cleanup on %q", w.pair[0])
return nil
}
}
diff --git a/internal/system/xhost.go b/internal/system/xhost.go
index 57168b81..89e63db5 100644
--- a/internal/system/xhost.go
+++ b/internal/system/xhost.go
@@ -24,18 +24,18 @@ func (x XHost) Type() Enablement {
}
func (x XHost) apply(_ *I) error {
- fmsg.VPrintf("inserting entry %s to X11", x)
+ fmsg.Verbosef("inserting entry %s to X11", x)
return fmsg.WrapErrorSuffix(xcb.ChangeHosts(xcb.HostModeInsert, xcb.FamilyServerInterpreted, "localuser\x00"+string(x)),
fmt.Sprintf("cannot insert entry %s to X11:", x))
}
func (x XHost) revert(_ *I, ec *Criteria) error {
if ec.hasType(x) {
- fmsg.VPrintf("deleting entry %s from X11", x)
+ fmsg.Verbosef("deleting entry %s from X11", x)
return fmsg.WrapErrorSuffix(xcb.ChangeHosts(xcb.HostModeDelete, xcb.FamilyServerInterpreted, "localuser\x00"+string(x)),
fmt.Sprintf("cannot delete entry %s from X11:", x))
} else {
- fmsg.VPrintf("skipping entry %s in X11", x)
+ fmsg.Verbosef("skipping entry %s in X11", x)
return nil
}
}
diff --git a/main.go b/main.go
index d925e56a..9883afc6 100644
--- a/main.go
+++ b/main.go
@@ -5,6 +5,7 @@ import (
_ "embed"
"flag"
"fmt"
+ "log"
"os"
"os/signal"
"os/user"
@@ -37,6 +38,8 @@ var (
)
func init() {
+ fmsg.Prepare("fortify")
+
flag.BoolVar(&flagVerbose, "v", false, "Verbose output")
flag.BoolVar(&flagJSON, "json", false, "Format output in JSON when applicable")
}
@@ -62,13 +65,12 @@ func main() {
init0.TryArgv0()
if err := internal.PR_SET_DUMPABLE__SUID_DUMP_DISABLE(); err != nil {
- fmsg.Printf("cannot set SUID_DUMP_DISABLE: %s", err)
+ log.Printf("cannot set SUID_DUMP_DISABLE: %s", err)
// not fatal: this program runs as the privileged user
}
if os.Geteuid() == 0 {
- fmsg.Fatal("this program must not run as root")
- panic("unreachable")
+ log.Fatal("this program must not run as root")
}
flag.CommandLine.Usage = func() {
@@ -96,12 +98,12 @@ func main() {
fmt.Println()
}
flag.Parse()
- fmsg.SetVerbose(flagVerbose)
+ fmsg.Store(flagVerbose)
args := flag.Args()
if len(args) == 0 {
flag.CommandLine.Usage()
- fmsg.Exit(0)
+ internal.Exit(0)
}
switch args[0] {
@@ -111,16 +113,20 @@ func main() {
} else {
fmt.Println("impure")
}
- fmsg.Exit(0)
+ internal.Exit(0)
+
case "license": // print embedded license
fmt.Println(license)
- fmsg.Exit(0)
+ internal.Exit(0)
+
case "template": // print full template configuration
printJSON(os.Stdout, false, fst.Template())
- fmsg.Exit(0)
+ internal.Exit(0)
+
case "help": // print help message
flag.CommandLine.Usage()
- fmsg.Exit(0)
+ internal.Exit(0)
+
case "ps": // print all state info
set := flag.NewFlagSet("ps", flag.ExitOnError)
var short bool
@@ -130,7 +136,8 @@ func main() {
_ = set.Parse(args[1:])
printPs(os.Stdout, time.Now().UTC(), state.NewMulti(sys.Paths().RunDirPath), short)
- fmsg.Exit(0)
+ internal.Exit(0)
+
case "show": // pretty-print app info
set := flag.NewFlagSet("show", flag.ExitOnError)
var short bool
@@ -142,6 +149,7 @@ func main() {
switch len(set.Args()) {
case 0: // system
printShowSystem(os.Stdout, short)
+
case 1: // instance
name := set.Args()[0]
config, instance := tryShort(name)
@@ -149,14 +157,15 @@ func main() {
config = tryPath(name)
}
printShowInstance(os.Stdout, time.Now().UTC(), instance, config, short)
+
default:
- fmsg.Fatal("show requires 1 argument")
+ log.Fatal("show requires 1 argument")
}
+ internal.Exit(0)
- fmsg.Exit(0)
case "app": // launch app from configuration file
if len(args) < 2 {
- fmsg.Fatal("app requires at least 1 argument")
+ log.Fatal("app requires at least 1 argument")
}
// config extraArgs...
@@ -166,6 +175,7 @@ func main() {
// invoke app
runApp(config)
panic("unreachable")
+
case "run": // run app in permissive defaults usage pattern
set := flag.NewFlagSet("run", flag.ExitOnError)
@@ -208,8 +218,7 @@ func main() {
}
if aid < 0 || aid > 9999 {
- fmsg.Fatalf("aid %d out of range", aid)
- panic("unreachable")
+ log.Fatalf("aid %d out of range", aid)
}
// resolve home/username from os when flag is unset
@@ -219,13 +228,13 @@ func main() {
passwdFunc = func() {
var us string
if uid, err := sys.Uid(aid); err != nil {
- fmsg.Fatalf("cannot obtain uid from fsu: %v", err)
+ log.Fatalf("cannot obtain uid from fsu: %v", err)
} else {
us = strconv.Itoa(uid)
}
if u, err := user.LookupId(us); err != nil {
- fmsg.VPrintf("cannot look up uid %s", us)
+ fmsg.Verbosef("cannot look up uid %s", us)
passwd = &user.User{
Uid: us,
Gid: us,
@@ -267,7 +276,7 @@ func main() {
config.Confinement.SessionBus = dbus.NewConfig(fid, true, mpris)
} else {
if c, err := dbus.NewConfigFromFile(dbusConfigSession); err != nil {
- fmsg.Fatalf("cannot load session bus proxy config from %q: %s", dbusConfigSession, err)
+ log.Fatalf("cannot load session bus proxy config from %q: %s", dbusConfigSession, err)
} else {
config.Confinement.SessionBus = c
}
@@ -276,7 +285,7 @@ func main() {
// system bus proxy is optional
if dbusConfigSystem != "nil" {
if c, err := dbus.NewConfigFromFile(dbusConfigSystem); err != nil {
- fmsg.Fatalf("cannot load system bus proxy config from %q: %s", dbusConfigSystem, err)
+ log.Fatalf("cannot load system bus proxy config from %q: %s", dbusConfigSystem, err)
} else {
config.Confinement.SystemBus = c
}
@@ -291,17 +300,18 @@ func main() {
// invoke app
runApp(config)
+ panic("unreachable")
// internal commands
case "shim":
shim.Main()
- fmsg.Exit(0)
+ internal.Exit(0)
case "init":
init0.Main()
- fmsg.Exit(0)
+ internal.Exit(0)
default:
- fmsg.Fatalf("%q is not a valid command", args[0])
+ log.Fatalf("%q is not a valid command", args[0])
}
panic("unreachable")
@@ -313,15 +323,15 @@ func runApp(config *fst.Config) {
syscall.SIGINT, syscall.SIGTERM)
defer stop() // unreachable
- if fmsg.Verbose() {
- seccomp.CPrintln = fmsg.Println
+ if fmsg.Load() {
+ seccomp.CPrintln = log.Println
}
if a, err := app.New(sys); err != nil {
- fmsg.Fatalf("cannot create app: %s\n", err)
+ log.Fatalf("cannot create app: %s", err)
} else if err = a.Seal(config); err != nil {
logBaseError(err, "cannot seal app:")
- fmsg.Exit(1)
+ internal.Exit(1)
} else if err = a.Run(ctx, rs); err != nil {
if !rs.Start {
logBaseError(err, "cannot start app:")
@@ -334,8 +344,7 @@ func runApp(config *fst.Config) {
}
}
if rs.WaitErr != nil {
- fmsg.Println("inner wait failed:", rs.WaitErr)
+ log.Println("inner wait failed:", rs.WaitErr)
}
- fmsg.Exit(rs.ExitCode)
- panic("unreachable")
+ internal.Exit(rs.ExitCode)
}
diff --git a/parse.go b/parse.go
index 85dbfca9..7212c92b 100644
--- a/parse.go
+++ b/parse.go
@@ -4,6 +4,7 @@ import (
"encoding/json"
"errors"
"io"
+ "log"
"os"
"strconv"
"strings"
@@ -21,11 +22,10 @@ func tryPath(name string) (config *fst.Config) {
if name != "-" {
r = tryFd(name)
if r == nil {
- fmsg.VPrintln("load configuration from file")
+ fmsg.Verbose("load configuration from file")
if f, err := os.Open(name); err != nil {
- fmsg.Fatalf("cannot access configuration file %q: %s", name, err)
- panic("unreachable")
+ log.Fatalf("cannot access configuration file %q: %s", name, err)
} else {
// finalizer closes f
r = f
@@ -33,7 +33,7 @@ func tryPath(name string) (config *fst.Config) {
} else {
defer func() {
if err := r.(io.ReadCloser).Close(); err != nil {
- fmsg.Printf("cannot close config fd: %v", err)
+ log.Printf("cannot close config fd: %v", err)
}
}()
}
@@ -42,8 +42,7 @@ func tryPath(name string) (config *fst.Config) {
}
if err := json.NewDecoder(r).Decode(&config); err != nil {
- fmsg.Fatalf("cannot load configuration: %v", err)
- panic("unreachable")
+ log.Fatalf("cannot load configuration: %v", err)
}
return
@@ -51,7 +50,7 @@ func tryPath(name string) (config *fst.Config) {
func tryFd(name string) io.ReadCloser {
if v, err := strconv.Atoi(name); err != nil {
- fmsg.VPrintf("name cannot be interpreted as int64: %v", err)
+ fmsg.Verbosef("name cannot be interpreted as int64: %v", err)
return nil
} else {
fd := uintptr(v)
@@ -59,7 +58,7 @@ func tryFd(name string) io.ReadCloser {
if errors.Is(errno, syscall.EBADF) {
return nil
}
- fmsg.Fatalf("cannot get fd %d: %v", fd, errno)
+ log.Fatalf("cannot get fd %d: %v", fd, errno)
}
return os.NewFile(fd, strconv.Itoa(v))
}
@@ -83,11 +82,11 @@ func tryShort(name string) (config *fst.Config, instance *state.State) {
// try to match from state store
if likePrefix && len(name) >= 8 {
- fmsg.VPrintln("argument looks like prefix")
+ fmsg.Verbose("argument looks like prefix")
s := state.NewMulti(sys.Paths().RunDirPath)
if entries, err := state.Join(s); err != nil {
- fmsg.Printf("cannot join store: %v", err)
+ log.Printf("cannot join store: %v", err)
// drop to fetch from file
} else {
for id := range entries {
@@ -99,7 +98,7 @@ func tryShort(name string) (config *fst.Config, instance *state.State) {
break
}
- fmsg.VPrintf("instance %s skipped", v)
+ fmsg.Verbosef("instance %s skipped", v)
}
}
}
diff --git a/print.go b/print.go
index 76603530..3c0c219d 100644
--- a/print.go
+++ b/print.go
@@ -4,6 +4,7 @@ import (
"encoding/json"
"fmt"
"io"
+ "log"
"slices"
"strconv"
"strings"
@@ -12,7 +13,6 @@ import (
"git.gensokyo.uk/security/fortify/dbus"
"git.gensokyo.uk/security/fortify/fst"
- "git.gensokyo.uk/security/fortify/internal/fmsg"
"git.gensokyo.uk/security/fortify/internal/state"
)
@@ -24,7 +24,7 @@ func printShowSystem(output io.Writer, short bool) {
// get fid by querying uid of aid 0
if uid, err := sys.Uid(0); err != nil {
- fmsg.Fatalf("cannot obtain uid from fsu: %v", err)
+ log.Fatalf("cannot obtain uid from fsu: %v", err)
} else {
info.User = (uid / 10000) - 100
}
@@ -190,12 +190,12 @@ func printShowInstance(
func printPs(output io.Writer, now time.Time, s state.Store, short bool) {
var entries state.Entries
if e, err := state.Join(s); err != nil {
- fmsg.Fatalf("cannot join store: %v", err)
+ log.Fatalf("cannot join store: %v", err)
} else {
entries = e
}
if err := s.Close(); err != nil {
- fmsg.Printf("cannot close store: %v", err)
+ log.Printf("cannot close store: %v", err)
}
if !short && flagJSON {
@@ -212,13 +212,13 @@ func printPs(output io.Writer, now time.Time, s state.Store, short bool) {
for id, instance := range entries {
// gracefully skip nil states
if instance == nil {
- fmsg.Printf("got invalid state entry %s", id.String())
+ log.Printf("got invalid state entry %s", id.String())
continue
}
// gracefully skip inconsistent states
if id != instance.ID {
- fmsg.Printf("possible store corruption: entry %s has id %s",
+ log.Printf("possible store corruption: entry %s has id %s",
id.String(), instance.ID.String())
continue
}
@@ -273,8 +273,7 @@ func printJSON(output io.Writer, short bool, v any) {
encoder.SetIndent("", " ")
}
if err := encoder.Encode(v); err != nil {
- fmsg.Fatalf("cannot serialise: %v", err)
- panic("unreachable")
+ log.Fatalf("cannot serialise: %v", err)
}
}
@@ -284,31 +283,26 @@ type tp struct{ *tabwriter.Writer }
func (p *tp) Printf(format string, a ...any) {
if _, err := fmt.Fprintf(p, format, a...); err != nil {
- fmsg.Fatalf("cannot write to tabwriter: %v", err)
- panic("unreachable")
+ log.Fatalf("cannot write to tabwriter: %v", err)
}
}
func (p *tp) Println(a ...any) {
if _, err := fmt.Fprintln(p, a...); err != nil {
- fmsg.Fatalf("cannot write to tabwriter: %v", err)
- panic("unreachable")
+ log.Fatalf("cannot write to tabwriter: %v", err)
}
}
func (p *tp) MustFlush() {
if err := p.Writer.Flush(); err != nil {
- fmsg.Fatalf("cannot flush tabwriter: %v", err)
- panic("unreachable")
+ log.Fatalf("cannot flush tabwriter: %v", err)
}
}
func mustPrint(output io.Writer, a ...any) {
if _, err := fmt.Fprint(output, a...); err != nil {
- fmsg.Fatalf("cannot print: %v", err)
- panic("unreachable")
+ log.Fatalf("cannot print: %v", err)
}
}
func mustPrintln(output io.Writer, a ...any) {
if _, err := fmt.Fprintln(output, a...); err != nil {
- fmsg.Fatalf("cannot print: %v", err)
- panic("unreachable")
+ log.Fatalf("cannot print: %v", err)
}
}