refactor: simplify service installation process
This commit is contained in:
12
README.md
12
README.md
@ -116,16 +116,10 @@ ss service reload [--name <name>] # reload config via mihomo's API, no restart
|
|||||||
ss service status [--name <name>]
|
ss service status [--name <name>]
|
||||||
```
|
```
|
||||||
|
|
||||||
Linux / macOS (installing the service needs root):
|
`install`/`uninstall`/`start`/`stop`/`restart` need root/admin privileges:
|
||||||
```bash
|
|
||||||
sudo env SF_CONFIG_DIR=$HOME/basicfiles/cli/ss ss service install
|
|
||||||
```
|
|
||||||
|
|
||||||
Windows (run from an elevated/Administrator shell):
|
- **Linux / macOS**: just run the command directly — `ss` re-execs itself under `sudo` automatically, prompting for your password if needed.
|
||||||
```powershell
|
- **Windows**: run from an elevated/Administrator shell — `ss.exe service install`.
|
||||||
$env:SF_CONFIG_DIR = "$HOME\basicfiles\cli\ss"
|
|
||||||
ss.exe service install
|
|
||||||
```
|
|
||||||
|
|
||||||
## Development
|
## Development
|
||||||
|
|
||||||
|
|||||||
57
internal/cli/elevate.go
Normal file
57
internal/cli/elevate.go
Normal 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)
|
||||||
|
}
|
||||||
@ -40,6 +40,9 @@ func newServiceInstallCmd() *cobra.Command {
|
|||||||
Short: "Install mihomo as a system service",
|
Short: "Install mihomo as a system service",
|
||||||
Args: cobra.NoArgs,
|
Args: cobra.NoArgs,
|
||||||
RunE: func(cmd *cobra.Command, args []string) error {
|
RunE: func(cmd *cobra.Command, args []string) error {
|
||||||
|
if err := ensureRoot(); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
m, err := newManagers("", "", "")
|
m, err := newManagers("", "", "")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
@ -62,6 +65,9 @@ func newServiceUninstallCmd() *cobra.Command {
|
|||||||
Short: "Uninstall mihomo system service",
|
Short: "Uninstall mihomo system service",
|
||||||
Args: cobra.NoArgs,
|
Args: cobra.NoArgs,
|
||||||
RunE: func(cmd *cobra.Command, args []string) error {
|
RunE: func(cmd *cobra.Command, args []string) error {
|
||||||
|
if err := ensureRoot(); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
m, err := newManagers("", "", "")
|
m, err := newManagers("", "", "")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
@ -83,6 +89,9 @@ func newServiceStartCmd() *cobra.Command {
|
|||||||
Short: "Start mihomo system service",
|
Short: "Start mihomo system service",
|
||||||
Args: cobra.NoArgs,
|
Args: cobra.NoArgs,
|
||||||
RunE: func(cmd *cobra.Command, args []string) error {
|
RunE: func(cmd *cobra.Command, args []string) error {
|
||||||
|
if err := ensureRoot(); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
m, err := newManagers("", "", "")
|
m, err := newManagers("", "", "")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
@ -104,6 +113,9 @@ func newServiceStopCmd() *cobra.Command {
|
|||||||
Short: "Stop mihomo system service",
|
Short: "Stop mihomo system service",
|
||||||
Args: cobra.NoArgs,
|
Args: cobra.NoArgs,
|
||||||
RunE: func(cmd *cobra.Command, args []string) error {
|
RunE: func(cmd *cobra.Command, args []string) error {
|
||||||
|
if err := ensureRoot(); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
m, err := newManagers("", "", "")
|
m, err := newManagers("", "", "")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
@ -125,6 +137,9 @@ func newServiceRestartCmd() *cobra.Command {
|
|||||||
Short: "Restart mihomo system service",
|
Short: "Restart mihomo system service",
|
||||||
Args: cobra.NoArgs,
|
Args: cobra.NoArgs,
|
||||||
RunE: func(cmd *cobra.Command, args []string) error {
|
RunE: func(cmd *cobra.Command, args []string) error {
|
||||||
|
if err := ensureRoot(); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
m, err := newManagers("", "", "")
|
m, err := newManagers("", "", "")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
|
|||||||
Reference in New Issue
Block a user