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.
This commit is contained in:
Cuong Manh Le
2024-05-16 14:35:31 +07:00
committed by Cuong Manh Le
parent 5710f2e984
commit 486096416f
3 changed files with 27 additions and 14 deletions
+8 -5
View File
@@ -850,7 +850,14 @@ NOTE: Uninstalling will set DNS to values provided by DHCP.`,
checkHasElevatedPrivilege() checkHasElevatedPrivilege()
}, },
Run: func(cmd *cobra.Command, args []string) { 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 { if err != nil {
mainLog.Load().Error().Msg(err.Error()) mainLog.Load().Error().Msg(err.Error())
return return
@@ -859,10 +866,6 @@ NOTE: Uninstalling will set DNS to values provided by DHCP.`,
if _, err := s.Status(); errors.Is(err, service.ErrNotInstalled) { if _, err := s.Status(); errors.Is(err, service.ErrNotInstalled) {
svcInstalled = false 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" oldBin := bin + "_previous"
baseUrl := upgradeChannel[upgradeChannelDefault] baseUrl := upgradeChannel[upgradeChannelDefault]
if len(args) > 0 { if len(args) > 0 {
+11 -5
View File
@@ -21,7 +21,7 @@ func newService(i service.Interface, c *service.Config) (service.Service, error)
} }
switch { switch {
case router.IsOldOpenwrt(), router.IsNetGearOrbi(): case router.IsOldOpenwrt(), router.IsNetGearOrbi():
return &procd{&sysV{s}}, nil return &procd{sysV: &sysV{s}, svcConfig: c}, nil
case router.IsGLiNet(): case router.IsGLiNet():
return &sysV{s}, nil return &sysV{s}, nil
case s.Platform() == "unix-systemv": case s.Platform() == "unix-systemv":
@@ -89,18 +89,24 @@ func (s *sysV) Status() (service.Status, error) {
// like old GL.iNET Opal router. // like old GL.iNET Opal router.
type procd struct { type procd struct {
*sysV *sysV
svcConfig *service.Config
} }
func (s *procd) Status() (service.Status, error) { func (s *procd) Status() (service.Status, error) {
if !s.installed() { if !s.installed() {
return service.StatusUnknown, service.ErrNotInstalled return service.StatusUnknown, service.ErrNotInstalled
} }
exe, err := os.Executable() bin := s.svcConfig.Executable
if err != nil { if bin == "" {
return service.StatusUnknown, nil exe, err := os.Executable()
if err != nil {
return service.StatusUnknown, nil
}
bin = exe
} }
// Looking for something like "/sbin/ctrld run ". // 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 { if err := exec.Command("sh", "-c", shellCmd).Run(); err != nil {
return service.StatusStopped, nil return service.StatusStopped, nil
} }
+8 -4
View File
@@ -49,11 +49,15 @@ func (s *merlinSvc) Platform() string {
} }
func (s *merlinSvc) configPath() string { func (s *merlinSvc) configPath() string {
path, err := os.Executable() bin := s.Config.Executable
if err != nil { if bin == "" {
return "" path, err := os.Executable()
if err != nil {
return ""
}
bin = path
} }
return path + ".startup" return bin + ".startup"
} }
func (s *merlinSvc) template() *template.Template { func (s *merlinSvc) template() *template.Template {