aboutsummaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
authorOphestra Umiker <cat@ophivana.moe>2024-11-04 23:08:29 +0900
committerOphestra Umiker <cat@ophivana.moe>2024-11-05 00:07:36 +0900
commit714818c8aa1a26450cdfac0828d1a9528fdb95a4 (patch)
tree2eb55d76b5cd885d915ca19033cff514dcafd5f4
parent69cc64ef56c4b46954514d7ef1b93b3861443255 (diff)
fortify: implement cleaner argument structure
Signed-off-by: Ophestra Umiker <cat@ophivana.moe>
-rw-r--r--config.go135
-rw-r--r--license.go25
-rw-r--r--main.go199
-rw-r--r--state.go35
-rw-r--r--version.go27
5 files changed, 187 insertions, 234 deletions
diff --git a/config.go b/config.go
deleted file mode 100644
index 261b59c5..00000000
--- a/config.go
+++ /dev/null
@@ -1,135 +0,0 @@
-package main
-
-import (
- "encoding/json"
- "flag"
- "fmt"
-
- "git.ophivana.moe/security/fortify/dbus"
- "git.ophivana.moe/security/fortify/internal/app"
- "git.ophivana.moe/security/fortify/internal/fmsg"
- "git.ophivana.moe/security/fortify/internal/system"
-)
-
-var (
- printTemplate bool
-
- confPath string
-
- dbusConfigSession string
- dbusConfigSystem string
- dbusID string
- mpris bool
- dbusVerbose bool
-
- userName string
- enablements [system.ELen]bool
-
- launchMethodText string
-)
-
-func init() {
- flag.BoolVar(&printTemplate, "template", false, "Print a full config template and exit")
-
- // config file, disables every other flag here
- flag.StringVar(&confPath, "c", "nil", "Path to full app configuration, or \"nil\" to configure from flags")
-
- flag.StringVar(&dbusConfigSession, "dbus-config", "builtin", "Path to D-Bus proxy config file, or \"builtin\" for defaults")
- flag.StringVar(&dbusConfigSystem, "dbus-system", "nil", "Path to system D-Bus proxy config file, or \"nil\" to disable")
- flag.StringVar(&dbusID, "dbus-id", "", "D-Bus ID of application, leave empty to disable own paths, has no effect if custom config is available")
- flag.BoolVar(&mpris, "mpris", false, "Allow owning MPRIS D-Bus path, has no effect if custom config is available")
- flag.BoolVar(&dbusVerbose, "dbus-log", false, "Force logging in the D-Bus proxy")
-
- flag.StringVar(&userName, "u", "chronos", "Passwd name of user to run as")
- flag.BoolVar(&enablements[system.EWayland], "wayland", false, "Share Wayland socket")
- flag.BoolVar(&enablements[system.EX11], "X", false, "Share X11 socket and allow connection")
- flag.BoolVar(&enablements[system.EDBus], "dbus", false, "Proxy D-Bus connection")
- flag.BoolVar(&enablements[system.EPulse], "pulse", false, "Share PulseAudio socket and cookie")
-}
-
-func init() {
- methodHelpString := "Method of launching the child process, can be one of \"sudo\""
- if os.SdBooted() {
- methodHelpString += ", \"systemd\""
- }
-
- flag.StringVar(&launchMethodText, "method", "sudo", methodHelpString)
-}
-
-func tryTemplate() {
- if printTemplate {
- if s, err := json.MarshalIndent(app.Template(), "", " "); err != nil {
- fmsg.Fatalf("cannot generate template: %v", err)
- panic("unreachable")
- } else {
- fmt.Println(string(s))
- }
- fmsg.Exit(0)
- }
-}
-
-func loadConfig() *app.Config {
- if confPath == "nil" {
- // config from flags
- return configFromFlags()
- } else {
- // config from file
- c := new(app.Config)
- if f, err := os.Open(confPath); err != nil {
- fmsg.Fatalf("cannot access config file %q: %s", confPath, err)
- panic("unreachable")
- } else if err = json.NewDecoder(f).Decode(&c); err != nil {
- fmsg.Fatalf("cannot parse config file %q: %s", confPath, err)
- panic("unreachable")
- } else {
- return c
- }
- }
-}
-
-func configFromFlags() (config *app.Config) {
- // initialise config from flags
- config = &app.Config{
- ID: dbusID,
- User: userName,
- Command: flag.Args(),
- Method: launchMethodText,
- }
-
- // enablements from flags
- for i := system.Enablement(0); i < system.Enablement(system.ELen); i++ {
- if enablements[i] {
- config.Confinement.Enablements.Set(i)
- }
- }
-
- // parse D-Bus config file from flags if applicable
- if enablements[system.EDBus] {
- if dbusConfigSession == "builtin" {
- config.Confinement.SessionBus = dbus.NewConfig(dbusID, true, mpris)
- } else {
- if c, err := dbus.NewConfigFromFile(dbusConfigSession); err != nil {
- fmsg.Fatalf("cannot load session bus proxy config from %q: %s", dbusConfigSession, err)
- } else {
- config.Confinement.SessionBus = c
- }
- }
-
- // 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)
- } else {
- config.Confinement.SystemBus = c
- }
- }
-
- // override log from configuration
- if dbusVerbose {
- config.Confinement.SessionBus.Log = true
- config.Confinement.SystemBus.Log = true
- }
- }
-
- return
-}
diff --git a/license.go b/license.go
deleted file mode 100644
index dbeede08..00000000
--- a/license.go
+++ /dev/null
@@ -1,25 +0,0 @@
-package main
-
-import (
- _ "embed"
- "flag"
- "fmt"
-)
-
-var (
- //go:embed LICENSE
- license string
-
- printLicense bool
-)
-
-func init() {
- flag.BoolVar(&printLicense, "license", false, "Print license")
-}
-
-func tryLicense() {
- if printLicense {
- fmt.Println(license)
- os.Exit(0)
- }
-}
diff --git a/main.go b/main.go
index 309af765..7c0a218d 100644
--- a/main.go
+++ b/main.go
@@ -1,16 +1,26 @@
package main
import (
+ _ "embed"
+ "encoding/json"
"flag"
+ "fmt"
+ "text/tabwriter"
+ "git.ophivana.moe/security/fortify/dbus"
"git.ophivana.moe/security/fortify/internal"
"git.ophivana.moe/security/fortify/internal/app"
"git.ophivana.moe/security/fortify/internal/fmsg"
"git.ophivana.moe/security/fortify/internal/linux"
+ "git.ophivana.moe/security/fortify/internal/state"
+ "git.ophivana.moe/security/fortify/internal/system"
)
var (
flagVerbose bool
+
+ //go:embed LICENSE
+ license string
)
func init() {
@@ -28,29 +38,193 @@ func main() {
flag.Parse()
fmsg.SetVerbose(flagVerbose)
- if os.SdBooted() {
- fmsg.VPrintln("system booted with systemd as init system")
- }
-
// root check
if os.Geteuid() == 0 {
fmsg.Fatal("this program must not run as root")
panic("unreachable")
}
- // version/license/template command early exit
- tryVersion()
- tryLicense()
- tryTemplate()
+ printHelp := func() {
+ fmt.Println()
+ fmt.Println("Usage:\tfortify [-v] COMMAND [OPTIONS]")
+ fmt.Println()
+ fmt.Println("Commands:")
+ w := tabwriter.NewWriter(os.Stdout(), 0, 1, 4, ' ', 0)
+ commands := [][2]string{
+ {"app", "Launch app defined by the specified config file"},
+ {"run", "Configure and start a permissive default sandbox"},
+ {"ps", "List active apps and their state"},
+ {"version", "Show fortify version"},
+ {"license", "Show full license text"},
+ {"template", "Produce a config template"},
+ {"help", "Show this help message"},
+ }
+ for _, c := range commands {
+ _, _ = fmt.Fprintf(w, "\t%s\t%s\n", c[0], c[1])
+ }
+ if err := w.Flush(); err != nil {
+ fmsg.Fatalf("cannot print help: %v", err)
+ }
+ fmt.Println()
+ }
+
+ args := flag.Args()
+ if len(args) == 0 {
+ printHelp()
+ fmsg.Exit(0)
+ }
+
+ switch args[0] {
+ case "version": // print version string
+ if v, ok := internal.Check(internal.Version); ok {
+ fmt.Println(v)
+ } else {
+ fmt.Println("impure")
+ }
+ fmsg.Exit(0)
+ case "license": // print embedded license
+ fmt.Println(license)
+ fmsg.Exit(0)
+ case "template": // print full template configuration
+ if s, err := json.MarshalIndent(app.Template(), "", " "); err != nil {
+ fmsg.Fatalf("cannot generate template: %v", err)
+ panic("unreachable")
+ } else {
+ fmt.Println(string(s))
+ }
+ fmsg.Exit(0)
+ case "help": // print help message
+ printHelp()
+ fmsg.Exit(0)
+ case "ps": // print all state info
+ var w *tabwriter.Writer
+ state.MustPrintLauncherStateSimpleGlobal(&w, os.Paths().RunDirPath)
+ if w != nil {
+ if err := w.Flush(); err != nil {
+ fmsg.Println("cannot format output:", err)
+ }
+ } else {
+ fmt.Println("No information available")
+ }
+
+ fmsg.Exit(0)
+ case "app": // launch app from configuration file
+ if len(args) < 2 {
+ fmsg.Fatal("app requires at least 1 argument")
+ }
+
+ config := new(app.Config)
+ if f, err := os.Open(args[1]); err != nil {
+ fmsg.Fatalf("cannot access config file %q: %s", args[1], err)
+ panic("unreachable")
+ } else if err = json.NewDecoder(f).Decode(&config); err != nil {
+ fmsg.Fatalf("cannot parse config file %q: %s", args[1], err)
+ panic("unreachable")
+ }
+
+ // append extra args
+ config.Command = append(config.Command, args[2:]...)
+
+ // invoke app
+ runApp(config)
+ case "run": // run app in permissive defaults usage pattern
+ set := flag.NewFlagSet("run", flag.ExitOnError)
+
+ var (
+ dbusConfigSession string
+ dbusConfigSystem string
+ dbusID string
+ mpris bool
+ dbusVerbose bool
+
+ userName string
+ enablements [system.ELen]bool
+
+ launchMethodText string
+ )
+
+ set.StringVar(&dbusConfigSession, "dbus-config", "builtin", "Path to D-Bus proxy config file, or \"builtin\" for defaults")
+ set.StringVar(&dbusConfigSystem, "dbus-system", "nil", "Path to system D-Bus proxy config file, or \"nil\" to disable")
+ set.StringVar(&dbusID, "dbus-id", "", "D-Bus ID of application, leave empty to disable own paths, has no effect if custom config is available")
+ set.BoolVar(&mpris, "mpris", false, "Allow owning MPRIS D-Bus path, has no effect if custom config is available")
+ set.BoolVar(&dbusVerbose, "dbus-log", false, "Force logging in the D-Bus proxy")
+
+ set.StringVar(&userName, "u", "chronos", "Passwd name of user to run as")
+ set.BoolVar(&enablements[system.EWayland], "wayland", false, "Share Wayland socket")
+ set.BoolVar(&enablements[system.EX11], "X", false, "Share X11 socket and allow connection")
+ set.BoolVar(&enablements[system.EDBus], "dbus", false, "Proxy D-Bus connection")
+ set.BoolVar(&enablements[system.EPulse], "pulse", false, "Share PulseAudio socket and cookie")
+
+ methodHelpString := "Method of launching the child process, can be one of \"sudo\""
+ if os.SdBooted() {
+ methodHelpString += ", \"systemd\""
+ }
+ set.StringVar(&launchMethodText, "method", "sudo", methodHelpString)
+
+ // Ignore errors; set is set for ExitOnError.
+ _ = set.Parse(args[1:])
+
+ // initialise config from flags
+ config := &app.Config{
+ ID: dbusID,
+ User: userName,
+ Command: set.Args(),
+ Method: launchMethodText,
+ }
+
+ // enablements from flags
+ for i := system.Enablement(0); i < system.Enablement(system.ELen); i++ {
+ if enablements[i] {
+ config.Confinement.Enablements.Set(i)
+ }
+ }
+
+ // parse D-Bus config file from flags if applicable
+ if enablements[system.EDBus] {
+ if dbusConfigSession == "builtin" {
+ config.Confinement.SessionBus = dbus.NewConfig(dbusID, true, mpris)
+ } else {
+ if c, err := dbus.NewConfigFromFile(dbusConfigSession); err != nil {
+ fmsg.Fatalf("cannot load session bus proxy config from %q: %s", dbusConfigSession, err)
+ } else {
+ config.Confinement.SessionBus = c
+ }
+ }
+
+ // 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)
+ } else {
+ config.Confinement.SystemBus = c
+ }
+ }
+
+ // override log from configuration
+ if dbusVerbose {
+ config.Confinement.SessionBus.Log = true
+ config.Confinement.SystemBus.Log = true
+ }
+ }
+
+ // invoke app
+ runApp(config)
+ default:
+ fmsg.Fatalf("%q is not a valid command", args[0])
+ }
+
+ panic("unreachable")
+}
- // state query command early exit
- tryState()
+func runApp(config *app.Config) {
+ if os.SdBooted() {
+ fmsg.VPrintln("system booted with systemd as init system")
+ }
- // invoke app
a, err := app.New(os)
if err != nil {
fmsg.Fatalf("cannot create app: %s\n", err)
- } else if err = a.Seal(loadConfig()); err != nil {
+ } else if err = a.Seal(config); err != nil {
logBaseError(err, "cannot seal app:")
fmsg.Exit(1)
} else if err = a.Start(); err != nil {
@@ -69,4 +243,5 @@ func main() {
fmsg.Println("inner wait failed:", err)
}
fmsg.Exit(r)
+ panic("unreachable")
}
diff --git a/state.go b/state.go
deleted file mode 100644
index 3a3f9a68..00000000
--- a/state.go
+++ /dev/null
@@ -1,35 +0,0 @@
-package main
-
-import (
- "flag"
- "fmt"
- "text/tabwriter"
-
- "git.ophivana.moe/security/fortify/internal/fmsg"
- "git.ophivana.moe/security/fortify/internal/state"
-)
-
-var (
- stateActionEarly bool
-)
-
-func init() {
- flag.BoolVar(&stateActionEarly, "state", false, "print state information of active launchers")
-}
-
-// tryState is called after app initialisation
-func tryState() {
- if stateActionEarly {
- var w *tabwriter.Writer
- state.MustPrintLauncherStateSimpleGlobal(&w, os.Paths().RunDirPath)
- if w != nil {
- if err := w.Flush(); err != nil {
- fmsg.Println("cannot format output:", err)
- }
- } else {
- fmt.Println("No information available")
- }
-
- fmsg.Exit(0)
- }
-}
diff --git a/version.go b/version.go
deleted file mode 100644
index 4028b160..00000000
--- a/version.go
+++ /dev/null
@@ -1,27 +0,0 @@
-package main
-
-import (
- "flag"
- "fmt"
-
- "git.ophivana.moe/security/fortify/internal"
-)
-
-var (
- printVersion bool
-)
-
-func init() {
- flag.BoolVar(&printVersion, "V", false, "Print version")
-}
-
-func tryVersion() {
- if printVersion {
- if v, ok := internal.Check(internal.Version); ok {
- fmt.Println(v)
- } else {
- fmt.Println("impure")
- }
- os.Exit(0)
- }
-}