From 486096416fcde408f59029f80cda3443b099d19e Mon Sep 17 00:00:00 2001 From: Cuong Manh Le Date: Wed, 15 May 2024 17:54:41 +0700 Subject: [PATCH] all: use correct binary path when running upgrade For safety reason, ctrld will create a backup of the current binary when running upgrade command. However, on systems where ctrld status is got by parsing ps command output, the current binary path is important and must be the same with the original binary. Depends on kernel version, using os.Executable may return new backup binary path, aka "ctrld_previous", not the original "ctrld" binary. This causes upgrade command see ctrld as not running after restart -> upgrade failed. Fixing this by recording the binary path before creating new service, so the ctrld service status can be checked correctly. --- cmd/cli/cli.go | 13 ++++++++----- cmd/cli/service.go | 16 +++++++++++----- internal/router/service_merlin.go | 12 ++++++++---- 3 files changed, 27 insertions(+), 14 deletions(-) diff --git a/cmd/cli/cli.go b/cmd/cli/cli.go index 3ae97f2..99054da 100644 --- a/cmd/cli/cli.go +++ b/cmd/cli/cli.go @@ -850,7 +850,14 @@ NOTE: Uninstalling will set DNS to values provided by DHCP.`, checkHasElevatedPrivilege() }, Run: func(cmd *cobra.Command, args []string) { - s, err := newService(&prog{}, svcConfig) + bin, err := os.Executable() + if err != nil { + mainLog.Load().Fatal().Err(err).Msg("failed to get current ctrld binary path") + } + sc := &service.Config{} + *sc = *svcConfig + sc.Executable = bin + s, err := newService(&prog{}, sc) if err != nil { mainLog.Load().Error().Msg(err.Error()) return @@ -859,10 +866,6 @@ NOTE: Uninstalling will set DNS to values provided by DHCP.`, if _, err := s.Status(); errors.Is(err, service.ErrNotInstalled) { svcInstalled = false } - bin, err := os.Executable() - if err != nil { - mainLog.Load().Fatal().Err(err).Msg("failed to get current ctrld binary path") - } oldBin := bin + "_previous" baseUrl := upgradeChannel[upgradeChannelDefault] if len(args) > 0 { diff --git a/cmd/cli/service.go b/cmd/cli/service.go index ef37796..1de206f 100644 --- a/cmd/cli/service.go +++ b/cmd/cli/service.go @@ -21,7 +21,7 @@ func newService(i service.Interface, c *service.Config) (service.Service, error) } switch { case router.IsOldOpenwrt(), router.IsNetGearOrbi(): - return &procd{&sysV{s}}, nil + return &procd{sysV: &sysV{s}, svcConfig: c}, nil case router.IsGLiNet(): return &sysV{s}, nil case s.Platform() == "unix-systemv": @@ -89,18 +89,24 @@ func (s *sysV) Status() (service.Status, error) { // like old GL.iNET Opal router. type procd struct { *sysV + svcConfig *service.Config } func (s *procd) Status() (service.Status, error) { if !s.installed() { return service.StatusUnknown, service.ErrNotInstalled } - exe, err := os.Executable() - if err != nil { - return service.StatusUnknown, nil + bin := s.svcConfig.Executable + if bin == "" { + exe, err := os.Executable() + if err != nil { + return service.StatusUnknown, nil + } + bin = exe } + // Looking for something like "/sbin/ctrld run ". - shellCmd := fmt.Sprintf("ps | grep -q %q", exe+" [r]un ") + shellCmd := fmt.Sprintf("ps | grep -q %q", bin+" [r]un ") if err := exec.Command("sh", "-c", shellCmd).Run(); err != nil { return service.StatusStopped, nil } diff --git a/internal/router/service_merlin.go b/internal/router/service_merlin.go index 76ea938..8ab6d6a 100644 --- a/internal/router/service_merlin.go +++ b/internal/router/service_merlin.go @@ -49,11 +49,15 @@ func (s *merlinSvc) Platform() string { } func (s *merlinSvc) configPath() string { - path, err := os.Executable() - if err != nil { - return "" + bin := s.Config.Executable + if bin == "" { + path, err := os.Executable() + if err != nil { + return "" + } + bin = path } - return path + ".startup" + return bin + ".startup" } func (s *merlinSvc) template() *template.Template {