diff options
Diffstat (limited to 'internal/app/setup.go')
| -rw-r--r-- | internal/app/setup.go | 124 |
1 files changed, 124 insertions, 0 deletions
diff --git a/internal/app/setup.go b/internal/app/setup.go new file mode 100644 index 00000000..7b5cd2ec --- /dev/null +++ b/internal/app/setup.go @@ -0,0 +1,124 @@ +package app + +import ( + "errors" + "fmt" + "os" + "os/exec" + "os/user" + "strconv" + + "git.ophivana.moe/cat/fortify/internal/state" + "git.ophivana.moe/cat/fortify/internal/system" + "git.ophivana.moe/cat/fortify/internal/util" +) + +type App struct { + uid int + env []string + command []string + + *user.User +} + +func (a *App) Run() { + f := a.launchBySudo + m, b := false, false + switch { + case system.MethodFlags[0]: // sudo + case system.MethodFlags[1]: // bare + m, b = true, true + default: // machinectl + m, b = true, false + } + + var toolPath string + + // dependency checks + const sudoFallback = "Falling back to 'sudo', some desktop integration features may not work" + if m { + if !util.SdBooted() { + fmt.Println("This system was not booted through systemd") + fmt.Println(sudoFallback) + } else if tp, ok := util.Which("machinectl"); !ok { + fmt.Println("Did not find 'machinectl' in PATH") + fmt.Println(sudoFallback) + } else { + toolPath = tp + f = func() []string { return a.launchByMachineCtl(b) } + } + } else if tp, ok := util.Which("sudo"); !ok { + state.Fatal("Did not find 'sudo' in PATH") + } else { + toolPath = tp + } + + if system.V.Verbose { + fmt.Printf("Selected launcher '%s' bare=%t\n", toolPath, b) + } + + cmd := exec.Command(toolPath, f()...) + cmd.Env = a.env + cmd.Stdin = os.Stdin + cmd.Stdout = os.Stdout + cmd.Stderr = os.Stderr + cmd.Dir = system.V.RunDir + + if system.V.Verbose { + fmt.Println("Executing:", cmd) + } + + if err := cmd.Start(); err != nil { + state.Fatal("Error starting process:", err) + } + + if err := state.SaveProcess(a.Uid, cmd); err != nil { + // process already started, shouldn't be fatal + fmt.Println("Error registering process:", err) + } + + var r int + if err := cmd.Wait(); err != nil { + var exitError *exec.ExitError + if !errors.As(err, &exitError) { + state.Fatal("Error running process:", err) + } + } + + if system.V.Verbose { + fmt.Println("Process exited with exit code", r) + } + state.BeforeExit() + os.Exit(r) +} + +func New(userName string, args []string) *App { + a := &App{command: args} + + if u, err := user.Lookup(userName); err != nil { + if errors.As(err, new(user.UnknownUserError)) { + fmt.Println("unknown user", userName) + } else { + // unreachable + panic(err) + } + + // too early for fatal + os.Exit(1) + } else { + a.User = u + } + + if u, err := strconv.Atoi(a.Uid); err != nil { + // usually unreachable + panic("uid parse") + } else { + a.uid = u + } + + if system.V.Verbose { + fmt.Println("Running as user", a.Username, "("+a.Uid+"),", "command:", a.command) + } + + return a +} |
