mirror of
https://github.com/Control-D-Inc/ctrld.git
synced 2026-02-03 22:18:39 +00:00
cmd/ctrld: support older GL-inet devices
The openwrt version in old GL-inet devices do not support checking status using /etc/init.d/<service_name>, so the sysV wrapping trick won't work. Instead, we need to parse "ps" command output to check whether ctrld process is running or not. While at it, making newService as a wrapper of service.New function, prevent the caller from calling the latter without following call to the former, causing mismatch in service operations.
This commit is contained in:
committed by
Cuong Manh Le
parent
e684c7d8c4
commit
60d6734e1f
@@ -131,11 +131,10 @@ func initCLI() {
|
||||
waitCh: waitCh,
|
||||
stopCh: stopCh,
|
||||
}
|
||||
s, err := service.New(p, svcConfig)
|
||||
s, err := newService(p, svcConfig)
|
||||
if err != nil {
|
||||
mainLog.Fatal().Err(err).Msg("failed create new service")
|
||||
}
|
||||
s = newService(s)
|
||||
if err := s.Run(); err != nil {
|
||||
mainLog.Error().Err(err).Msg("failed to start service")
|
||||
}
|
||||
@@ -305,12 +304,11 @@ func initCLI() {
|
||||
}
|
||||
|
||||
prog := &prog{}
|
||||
s, err := service.New(prog, sc)
|
||||
s, err := newService(prog, sc)
|
||||
if err != nil {
|
||||
mainLog.Error().Msg(err.Error())
|
||||
return
|
||||
}
|
||||
s = newService(s)
|
||||
tasks := []task{
|
||||
{s.Stop, false},
|
||||
{s.Uninstall, false},
|
||||
@@ -322,7 +320,7 @@ func initCLI() {
|
||||
mainLog.Warn().Err(err).Msg("post installation failed, please check system/service log for details error")
|
||||
return
|
||||
}
|
||||
status, err := serviceStatus(s)
|
||||
status, err := s.Status()
|
||||
if err != nil {
|
||||
mainLog.Warn().Err(err).Msg("could not get service status")
|
||||
return
|
||||
@@ -370,12 +368,11 @@ func initCLI() {
|
||||
Args: cobra.NoArgs,
|
||||
Run: func(cmd *cobra.Command, args []string) {
|
||||
prog := &prog{}
|
||||
s, err := service.New(prog, svcConfig)
|
||||
s, err := newService(prog, svcConfig)
|
||||
if err != nil {
|
||||
mainLog.Error().Msg(err.Error())
|
||||
return
|
||||
}
|
||||
s = newService(s)
|
||||
initLogging()
|
||||
if doTasks([]task{{s.Stop, true}}) {
|
||||
prog.resetDNS()
|
||||
@@ -394,12 +391,11 @@ func initCLI() {
|
||||
Short: "Restart the ctrld service",
|
||||
Args: cobra.NoArgs,
|
||||
Run: func(cmd *cobra.Command, args []string) {
|
||||
s, err := service.New(&prog{}, svcConfig)
|
||||
s, err := newService(&prog{}, svcConfig)
|
||||
if err != nil {
|
||||
mainLog.Error().Msg(err.Error())
|
||||
return
|
||||
}
|
||||
s = newService(s)
|
||||
initLogging()
|
||||
if doTasks([]task{{s.Restart, true}}) {
|
||||
mainLog.Notice().Msg("Service restarted")
|
||||
@@ -415,13 +411,12 @@ func initCLI() {
|
||||
initConsoleLogging()
|
||||
},
|
||||
Run: func(cmd *cobra.Command, args []string) {
|
||||
s, err := service.New(&prog{}, svcConfig)
|
||||
s, err := newService(&prog{}, svcConfig)
|
||||
if err != nil {
|
||||
mainLog.Error().Msg(err.Error())
|
||||
return
|
||||
}
|
||||
s = newService(s)
|
||||
status, err := serviceStatus(s)
|
||||
status, err := s.Status()
|
||||
if err != nil {
|
||||
mainLog.Error().Msg(err.Error())
|
||||
os.Exit(1)
|
||||
@@ -460,7 +455,7 @@ NOTE: Uninstalling will set DNS to values provided by DHCP.`,
|
||||
Args: cobra.NoArgs,
|
||||
Run: func(cmd *cobra.Command, args []string) {
|
||||
prog := &prog{}
|
||||
s, err := service.New(prog, svcConfig)
|
||||
s, err := newService(prog, svcConfig)
|
||||
if err != nil {
|
||||
mainLog.Error().Msg(err.Error())
|
||||
return
|
||||
@@ -712,12 +707,11 @@ func processCDFlags() {
|
||||
logger.Info().Msgf("fetching Controld D configuration from API: %s", cdUID)
|
||||
resolverConfig, err := controld.FetchResolverConfig(cdUID, rootCmd.Version, cdDev)
|
||||
if uer, ok := err.(*controld.UtilityErrorResponse); ok && uer.ErrorField.Code == controld.InvalidConfigCode {
|
||||
s, err := service.New(&prog{}, svcConfig)
|
||||
s, err := newService(&prog{}, svcConfig)
|
||||
if err != nil {
|
||||
logger.Warn().Err(err).Msg("failed to create new service")
|
||||
return
|
||||
}
|
||||
|
||||
if netIface, _ := netInterface(iface); netIface != nil {
|
||||
if err := restoreNetworkManager(); err != nil {
|
||||
logger.Error().Err(err).Msg("could not restore NetworkManager")
|
||||
|
||||
@@ -3,6 +3,7 @@ package main
|
||||
import (
|
||||
"bytes"
|
||||
"errors"
|
||||
"fmt"
|
||||
"os"
|
||||
"os/exec"
|
||||
|
||||
@@ -11,37 +12,87 @@ import (
|
||||
"github.com/Control-D-Inc/ctrld/internal/router"
|
||||
)
|
||||
|
||||
func newService(s service.Service) service.Service {
|
||||
// TODO: unify for other SysV system.
|
||||
switch {
|
||||
case router.IsGLiNet(), router.IsOldOpenwrt():
|
||||
return &sysV{s}
|
||||
// newService wraps service.New call to return service.Service
|
||||
// wrapper which is suitable for the current platform.
|
||||
func newService(i service.Interface, c *service.Config) (service.Service, error) {
|
||||
s, err := service.New(i, c)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return s
|
||||
switch {
|
||||
case router.IsOldOpenwrt():
|
||||
return &procd{&sysV{s}}, nil
|
||||
case router.IsGLiNet(): // TODO: unify for other SysV system.
|
||||
return &sysV{s}, nil
|
||||
}
|
||||
return s, nil
|
||||
}
|
||||
|
||||
// sysV wraps a service.Service, and provide start/stop/status command
|
||||
// base on "/etc/init.d/<service_name>".
|
||||
//
|
||||
// Use this on system wherer "service" command is not available, like GL.iNET router.
|
||||
// Use this on system where "service" command is not available, like GL.iNET router.
|
||||
type sysV struct {
|
||||
service.Service
|
||||
}
|
||||
|
||||
func (s *sysV) installed() bool {
|
||||
fi, err := os.Stat("/etc/init.d/ctrld")
|
||||
if err != nil {
|
||||
return false
|
||||
}
|
||||
mode := fi.Mode()
|
||||
return mode.IsRegular() && (mode&0111) != 0
|
||||
}
|
||||
|
||||
func (s *sysV) Start() error {
|
||||
if !s.installed() {
|
||||
return service.ErrNotInstalled
|
||||
}
|
||||
_, err := exec.Command("/etc/init.d/ctrld", "start").CombinedOutput()
|
||||
return err
|
||||
}
|
||||
|
||||
func (s *sysV) Stop() error {
|
||||
if !s.installed() {
|
||||
return service.ErrNotInstalled
|
||||
}
|
||||
_, err := exec.Command("/etc/init.d/ctrld", "stop").CombinedOutput()
|
||||
return err
|
||||
}
|
||||
|
||||
func (s *sysV) Status() (service.Status, error) {
|
||||
if !s.installed() {
|
||||
return service.StatusUnknown, service.ErrNotInstalled
|
||||
}
|
||||
return unixSystemVServiceStatus()
|
||||
}
|
||||
|
||||
// procd wraps a service.Service, and provide start/stop command
|
||||
// base on "/etc/init.d/<service_name>", status command base on parsing "ps" command output.
|
||||
//
|
||||
// Use this on system where "/etc/init.d/<service_name> status" command is not available,
|
||||
// like old GL.iNET Opal router.
|
||||
type procd struct {
|
||||
*sysV
|
||||
}
|
||||
|
||||
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
|
||||
}
|
||||
// Looking for something like "/sbin/ctrld run ".
|
||||
shellCmd := fmt.Sprintf("ps | grep -q %q", exe+" [r]un ")
|
||||
if err := exec.Command("sh", "-c", shellCmd).Run(); err != nil {
|
||||
return service.StatusStopped, nil
|
||||
}
|
||||
return service.StatusRunning, nil
|
||||
}
|
||||
|
||||
type task struct {
|
||||
f func() error
|
||||
abortOnError bool
|
||||
@@ -73,14 +124,6 @@ func checkHasElevatedPrivilege() {
|
||||
}
|
||||
}
|
||||
|
||||
func serviceStatus(s service.Service) (service.Status, error) {
|
||||
status, err := s.Status()
|
||||
if err != nil && service.Platform() == "unix-systemv" {
|
||||
return unixSystemVServiceStatus()
|
||||
}
|
||||
return status, err
|
||||
}
|
||||
|
||||
func unixSystemVServiceStatus() (service.Status, error) {
|
||||
out, err := exec.Command("/etc/init.d/ctrld", "status").CombinedOutput()
|
||||
if err != nil {
|
||||
|
||||
Reference in New Issue
Block a user