refactor: simplify service installation process

This commit is contained in:
2026-07-19 20:07:26 +08:00
parent a2630df9e0
commit dcdb54b76c
3 changed files with 75 additions and 9 deletions

57
internal/cli/elevate.go Normal file
View File

@ -0,0 +1,57 @@
package cli
import (
"fmt"
"os"
"os/exec"
"runtime"
"gitea.epss.net.cn/klesh/ss/internal/storage"
)
// ensureRoot re-execs the current command under sudo if it isn't already
// running as root. It resolves the config directory *before* elevating and
// passes it through explicitly as SF_CONFIG_DIR, because sudo resets $HOME
// to /root's — without this, the elevated process would silently resolve
// the default config directory under /root instead of the invoking user's
// home.
//
// Windows is handled separately: UAC elevation launches a new process that
// can't transparently inherit the current console, so internal/service's
// runAsAdmin instead prints manual elevation instructions rather than
// auto-elevating.
func ensureRoot() error {
if runtime.GOOS == "windows" {
return nil
}
if os.Geteuid() == 0 {
return nil
}
s, err := storage.New()
if err != nil {
return fmt.Errorf("failed to resolve config directory: %w", err)
}
self, err := os.Executable()
if err != nil {
return fmt.Errorf("failed to determine executable path: %w", err)
}
sudoPath, err := exec.LookPath("sudo")
if err != nil {
return fmt.Errorf("this command requires root privileges, but sudo was not found on PATH: %w", err)
}
args := append([]string{"env", "SF_CONFIG_DIR=" + s.ConfigDir, self}, os.Args[1:]...)
cmd := exec.Command(sudoPath, args...)
cmd.Stdin = os.Stdin
cmd.Stdout = os.Stdout
cmd.Stderr = os.Stderr
runErr := cmd.Run()
if cmd.ProcessState != nil {
os.Exit(cmd.ProcessState.ExitCode())
}
return fmt.Errorf("failed to re-exec under sudo: %w", runErr)
}