58 lines
1.6 KiB
Go
58 lines
1.6 KiB
Go
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)
|
|
}
|