From ee1fd0863b657779e495157a7760cfdd12ab111c Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 15 Jul 2025 05:33:10 +0000 Subject: [PATCH] Bump github.com/kardianos/service from 1.2.2 to 1.2.4 Bumps [github.com/kardianos/service](https://github.com/kardianos/service) from 1.2.2 to 1.2.4. - [Commits](https://github.com/kardianos/service/compare/v1.2.2...v1.2.4) --- updated-dependencies: - dependency-name: github.com/kardianos/service dependency-version: 1.2.4 dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- go.mod | 2 +- go.sum | 5 +- .../github.com/kardianos/service/service.go | 121 ++++--- .../kardianos/service/service_aix.go | 114 ++++--- .../kardianos/service/service_freebsd.go | 8 +- .../kardianos/service/service_go1.8.go | 3 +- .../kardianos/service/service_linux.go | 80 ++++- .../kardianos/service/service_procd_linux.go | 175 ++++++++++ .../kardianos/service/service_rcs_linux.go | 312 ++++++++++++++++++ .../service/service_systemd_linux.go | 9 +- vendor/modules.txt | 4 +- 11 files changed, 722 insertions(+), 111 deletions(-) create mode 100644 vendor/github.com/kardianos/service/service_procd_linux.go create mode 100644 vendor/github.com/kardianos/service/service_rcs_linux.go diff --git a/go.mod b/go.mod index cb6f5ae7ad..2d423641b0 100644 --- a/go.mod +++ b/go.mod @@ -19,7 +19,7 @@ require ( github.com/jedisct1/go-sieve-cache v0.1.7 github.com/jedisct1/xsecretbox v0.0.0-20241212092125-3afc4917ac41 github.com/k-sone/critbitgo v1.4.0 - github.com/kardianos/service v1.2.2 + github.com/kardianos/service v1.2.4 github.com/lifenjoiner/dhcpdns v0.0.7 github.com/miekg/dns v1.1.67 github.com/powerman/check v1.8.0 diff --git a/go.sum b/go.sum index 2dbdb3d6c9..2a755a4471 100644 --- a/go.sum +++ b/go.sum @@ -48,8 +48,8 @@ github.com/jtolds/gls v4.20.0+incompatible h1:xdiiI2gbIgH/gLH7ADydsJ1uDOEzR8yvV7 github.com/jtolds/gls v4.20.0+incompatible/go.mod h1:QJZ7F/aHp+rZTRtaJ1ow/lLfFfVYBRgL+9YlvaHOwJU= github.com/k-sone/critbitgo v1.4.0 h1:l71cTyBGeh6X5ATh6Fibgw3+rtNT80BA0uNNWgkPrbE= github.com/k-sone/critbitgo v1.4.0/go.mod h1:7E6pyoyADnFxlUBEKcnfS49b7SUAQGMK+OAp/UQvo0s= -github.com/kardianos/service v1.2.2 h1:ZvePhAHfvo0A7Mftk/tEzqEZ7Q4lgnR8sGz4xu1YX60= -github.com/kardianos/service v1.2.2/go.mod h1:CIMRFEJVL+0DS1a3Nx06NaMn4Dz63Ng6O7dl0qH0zVM= +github.com/kardianos/service v1.2.4 h1:XNlGtZOYNx2u91urOdg/Kfmc+gfmuIo1Dd3rEi2OgBk= +github.com/kardianos/service v1.2.4/go.mod h1:E4V9ufUuY82F7Ztlu1eN9VXWIQxg8NoLQlmFe0MtrXc= github.com/lifenjoiner/dhcpdns v0.0.7 h1:VJM2aFWHU9V7M5v4UYYNaHhIHZkbdvSI6WGGpq6/TNQ= github.com/lifenjoiner/dhcpdns v0.0.7/go.mod h1:BixeaGeafYzDIuDCYIUbSOdi4m+TScpzI9cZGYgzgSk= github.com/miekg/dns v1.1.67 h1:kg0EHj0G4bfT5/oOys6HhZw4vmMlnoZ+gDu8tJ/AlI0= @@ -83,7 +83,6 @@ golang.org/x/net v0.42.0/go.mod h1:FF1RA5d3u7nAYA4z2TkclSCKh68eSXtiFwcWQpPXdt8= golang.org/x/sync v0.16.0 h1:ycBJEhp9p4vXvUZNszeOq0kGTPghopOL8q0fq3vstxw= golang.org/x/sync v0.16.0/go.mod h1:1dzgHSNfp02xaA81J2MS99Qcpr2w7fw1gpm99rleRqA= golang.org/x/sys v0.0.0-20190529164535-6a60838ec259/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20201015000850-e3ed0017c211/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.34.0 h1:H5Y5sJ2L2JRdyv7ROF1he/lPdvFsd0mJHFw2ThKHxLA= golang.org/x/sys v0.34.0/go.mod h1:BJP2sWEmIv4KK5OTEluFJCKSidICx8ciO85XgH3Ak8k= golang.org/x/text v0.27.0 h1:4fGWRpyh641NLlecmyl4LOe6yDdfaYNrGb2zdfo4JV4= diff --git a/vendor/github.com/kardianos/service/service.go b/vendor/github.com/kardianos/service/service.go index 5b564ea83c..130fc22d48 100644 --- a/vendor/github.com/kardianos/service/service.go +++ b/vendor/github.com/kardianos/service/service.go @@ -91,6 +91,7 @@ const ( optionSystemdScript = "SystemdScript" optionSysvScript = "SysvScript" + optionRCSScript = "RCSScript" optionUpstartScript = "UpstartScript" optionLaunchdConfig = "LaunchdConfig" optionOpenRCScript = "OpenRCScript" @@ -166,42 +167,70 @@ func New(i Interface, c *Config) (Service, error) { } // KeyValue provides a list of system specific options. -// * OS X -// - LaunchdConfig string () - Use custom launchd config. -// - KeepAlive bool (true) - Prevent the system from stopping the service automatically. -// - RunAtLoad bool (false) - Run the service after its job has been loaded. -// - SessionCreate bool (false) - Create a full user session. -// -// * Solaris -// - Prefix string ("application") - Service FMRI prefix. -// -// * POSIX -// - UserService bool (false) - Install as a current user service. -// - SystemdScript string () - Use custom systemd script. -// - UpstartScript string () - Use custom upstart script. -// - SysvScript string () - Use custom sysv script. -// - OpenRCScript string () - Use custom OpenRC script. -// - RunWait func() (wait for SIGNAL) - Do not install signal but wait for this function to return. -// - ReloadSignal string () [USR1, ...] - Signal to send on reload. -// - PIDFile string () [/run/prog.pid] - Location of the PID file. -// - LogOutput bool (false) - Redirect StdErr & StandardOutPath to files. -// - Restart string (always) - How shall service be restarted. -// - SuccessExitStatus string () - The list of exit status that shall be considered as successful, -// in addition to the default ones. -// - LogDirectory string(/var/log) - The path to the log files directory -// -// * Linux (systemd) -// - LimitNOFILE int (-1) - Maximum open files (ulimit -n) -// (https://serverfault.com/questions/628610/increasing-nproc-for-processes-launched-by-systemd-on-centos-7) -// * Windows -// - DelayedAutoStart bool (false) - After booting, start this service after some delay. -// - Password string () - Password to use when interfacing with the system service manager. -// - Interactive bool (false) - The service can interact with the desktop. (more information https://docs.microsoft.com/en-us/windows/win32/services/interactive-services) -// - DelayedAutoStart bool (false) - after booting start this service after some delay. -// - StartType string ("automatic") - Start service type. (automatic | manual | disabled) -// - OnFailure string ("restart" ) - Action to perform on service failure. (restart | reboot | noaction) -// - OnFailureDelayDuration string ( "1s" ) - Delay before restarting the service, time.Duration string. -// - OnFailureResetPeriod int ( 10 ) - Reset period for errors, seconds. +// +// - OS X +// +// - LaunchdConfig string () - Use custom launchd config. +// +// - KeepAlive bool (true) - Prevent the system from stopping the service automatically. +// +// - RunAtLoad bool (false) - Run the service after its job has been loaded. +// +// - SessionCreate bool (false) - Create a full user session. +// +// - Solaris +// +// - Prefix string ("application") - Service FMRI prefix. +// +// - POSIX +// +// - UserService bool (false) - Install as a current user service. +// +// - SystemdScript string () - Use custom systemd script. +// +// - UpstartScript string () - Use custom upstart script. +// +// - SysvScript string () - Use custom sysv script. +// +// - OpenRCScript string () - Use custom OpenRC script. +// +// - RunWait func() (wait for SIGNAL) - Do not install signal but wait for this function to return. +// +// - ReloadSignal string () [USR1, ...] - Signal to send on reload. +// +// - PIDFile string () [/run/prog.pid] - Location of the PID file. +// +// - LogOutput bool (false) - Redirect StdErr & StandardOutPath to files. +// +// - Restart string (always) - How shall service be restarted. +// +// - SuccessExitStatus string () - The list of exit status that shall be considered as successful, +// in addition to the default ones. +// +// - LogDirectory string(/var/log) - The path to the log files directory +// +// - Linux (systemd) +// +// - LimitNOFILE int (-1) - Maximum open files (ulimit -n) +// (https://serverfault.com/questions/628610/increasing-nproc-for-processes-launched-by-systemd-on-centos-7) +// +// - Windows +// +// - DelayedAutoStart bool (false) - After booting, start this service after some delay. +// +// - Password string () - Password to use when interfacing with the system service manager. +// +// - Interactive bool (false) - The service can interact with the desktop. (more information https://docs.microsoft.com/en-us/windows/win32/services/interactive-services) +// +// - DelayedAutoStart bool (false) - after booting start this service after some delay. +// +// - StartType string ("automatic") - Start service type. (automatic | manual | disabled) +// +// - OnFailure string ("restart" ) - Action to perform on service failure. (restart | reboot | noaction) +// +// - OnFailureDelayDuration string ( "1s" ) - Delay before restarting the service, time.Duration string. +// +// - OnFailureResetPeriod int ( 10 ) - Reset period for errors, seconds. type KeyValue map[string]interface{} // bool returns the value of the given name, assuming the value is a boolean. @@ -324,16 +353,16 @@ type System interface { // Interface represents the service interface for a program. Start runs before // the hosting process is granted control and Stop runs when control is returned. // -// 1. OS service manager executes user program. -// 2. User program sees it is executed from a service manager (IsInteractive is false). -// 3. User program calls Service.Run() which blocks. -// 4. Interface.Start() is called and quickly returns. -// 5. User program runs. -// 6. OS service manager signals the user program to stop. -// 7. Interface.Stop() is called and quickly returns. -// - For a successful exit, os.Exit should not be called in Interface.Stop(). -// 8. Service.Run returns. -// 9. User program should quickly exit. +// 1. OS service manager executes user program. +// 2. User program sees it is executed from a service manager (IsInteractive is false). +// 3. User program calls Service.Run() which blocks. +// 4. Interface.Start() is called and quickly returns. +// 5. User program runs. +// 6. OS service manager signals the user program to stop. +// 7. Interface.Stop() is called and quickly returns. +// - For a successful exit, os.Exit should not be called in Interface.Stop(). +// 8. Service.Run returns. +// 9. User program should quickly exit. type Interface interface { // Start provides a place to initiate the service. The service doesn't // signal a completed start until after this function returns, so the diff --git a/vendor/github.com/kardianos/service/service_aix.go b/vendor/github.com/kardianos/service/service_aix.go index 505c3ae0bf..de7a907272 100644 --- a/vendor/github.com/kardianos/service/service_aix.go +++ b/vendor/github.com/kardianos/service/service_aix.go @@ -1,4 +1,5 @@ -//+build aix +//go:build aix +// +build aix // Copyright 2015 Daniel Theophanes. // Use of this source code is governed by a zlib-style @@ -8,6 +9,7 @@ package service import ( "bytes" + "errors" "fmt" "os" "os/exec" @@ -20,30 +22,33 @@ import ( "time" ) -const maxPathSize = 32 * 1024 - -const version = "aix-ssrc" +const ( + maxPathSize = 32 * 1024 + version = "aix-ssrc" +) type aixSystem struct{} func (aixSystem) String() string { return version } + func (aixSystem) Detect() bool { return true } + func (aixSystem) Interactive() bool { return interactive } + func (aixSystem) New(i Interface, c *Config) (Service, error) { - s := &aixService{ + return &aixService{ i: i, Config: c, - } - - return s, nil + }, nil } +// Retrieve process arguments from a PID. func getArgsFromPid(pid int) string { cmd := exec.Command("ps", "-o", "args", "-p", strconv.Itoa(pid)) var out bytes.Buffer @@ -57,23 +62,22 @@ func getArgsFromPid(pid int) string { return "" } -func init() { - ChooseSystem(aixSystem{}) -} - var interactive = false func init() { + ChooseSystem(aixSystem{}) + var err error interactive, err = isInteractive() if err != nil { - panic(err) + panic(fmt.Sprintf("Failed to determine if interactive: %v", err)) } } +// Check if the process is running interactively. func isInteractive() (bool, error) { - // The parent process of a service process should be srcmstr. - return getArgsFromPid(os.Getppid()) != "/usr/sbin/srcmstr", nil + parentArgs := getArgsFromPid(os.Getppid()) + return parentArgs != "/usr/sbin/srcmstr", nil } type aixService struct { @@ -103,37 +107,37 @@ func (s *aixService) template() *template.Template { } customConfig := s.Option.string(optionSysvScript, "") - if customConfig != "" { return template.Must(template.New("").Funcs(functions).Parse(customConfig)) - } else { - return template.Must(template.New("").Funcs(functions).Parse(svcConfig)) } + return template.Must(template.New("").Funcs(functions).Parse(svcConfig)) } -func (s *aixService) configPath() (cp string, err error) { - cp = "/etc/rc.d/init.d/" + s.Config.Name - return +func (s *aixService) configPath() (string, error) { + return "/etc/rc.d/init.d/" + s.Config.Name, nil } func (s *aixService) Install() error { - // install service + // Install service path, err := s.execPath() if err != nil { return err } - err = run("mkssys", "-s", s.Name, "-p", path, "-u", "0", "-R", "-Q", "-S", "-n", "15", "-f", "9", "-d", "-w", "30") + if len(s.Config.Arguments) > 0 { + err = run("mkssys", "-s", s.Name, "-p", path, "-a", strings.Join(s.Config.Arguments, " "), "-u", "0", "-R", "-Q", "-S", "-n", "15", "-f", "9", "-d", "-w", "30") + } else { + err = run("mkssys", "-s", s.Name, "-p", path, "-u", "0", "-R", "-Q", "-S", "-n", "15", "-f", "9", "-d", "-w", "30") + } if err != nil { return err } - // write start script + // Write start script confPath, err := s.configPath() if err != nil { return err } - _, err = os.Stat(confPath) - if err == nil { + if _, err = os.Stat(confPath); err == nil { return fmt.Errorf("Init already exists: %s", confPath) } @@ -143,31 +147,32 @@ func (s *aixService) Install() error { } defer f.Close() - var to = &struct { + to := struct { *Config Path string }{ - s.Config, - path, + Config: s.Config, + Path: path, } - err = s.template().Execute(f, to) - if err != nil { + if err = s.template().Execute(f, &to); err != nil { return err } if err = os.Chmod(confPath, 0755); err != nil { return err } + rcd := "/etc/rc" if _, err = os.Stat("/etc/rc.d/rc2.d"); err == nil { rcd = "/etc/rc.d/rc" } + for _, i := range [...]string{"2", "3"} { - if err = os.Symlink(confPath, rcd+i+".d/S50"+s.Name); err != nil { + if err = os.Symlink(confPath, fmt.Sprintf("%s%s.d/S50%s", rcd, i, s.Name)); err != nil { continue } - if err = os.Symlink(confPath, rcd+i+".d/K02"+s.Name); err != nil { + if err = os.Symlink(confPath, fmt.Sprintf("%s%s.d/K02%s", rcd, i, s.Name)); err != nil { continue } } @@ -176,10 +181,11 @@ func (s *aixService) Install() error { } func (s *aixService) Uninstall() error { - s.Stop() + if err := s.Stop(); err != nil { + return err + } - err := run("rmssys", "-s", s.Name) - if err != nil { + if err := run("rmssys", "-s", s.Name); err != nil { return err } @@ -198,17 +204,17 @@ func (s *aixService) Status() (Status, error) { } } - re := regexp.MustCompile(`\s+` + s.Name + `\s+(\w+\s+)?(\d+\s+)?(\w+)`) + re := regexp.MustCompile(`\s+` + regexp.QuoteMeta(s.Name) + `\s+(\w+\s+)?(\d+\s+)?(\w+)`) matches := re.FindStringSubmatch(out) if len(matches) == 4 { - status := string(matches[3]) - if status == "inoperative" { + switch matches[3] { + case "inoperative": return StatusStopped, nil - } else if status == "active" { + case "active": return StatusRunning, nil - } else { - fmt.Printf("Got unknown service status %s\n", status) - return StatusUnknown, err + default: + fmt.Printf("Got unknown service status %s\n", matches[3]) + return StatusUnknown, errors.New("unknown status") } } @@ -227,12 +233,13 @@ func (s *aixService) Status() (Status, error) { func (s *aixService) Start() error { return run("startsrc", "-s", s.Name) } + func (s *aixService) Stop() error { return run("stopsrc", "-s", s.Name) } + func (s *aixService) Restart() error { - err := s.Stop() - if err != nil { + if err := s.Stop(); err != nil { return err } time.Sleep(50 * time.Millisecond) @@ -240,15 +247,12 @@ func (s *aixService) Restart() error { } func (s *aixService) Run() error { - var err error - - err = s.i.Start(s) - if err != nil { + if err := s.i.Start(s); err != nil { return err } s.Option.funcSingle(optionRunWait, func() { - var sigChan = make(chan os.Signal, 3) + sigChan := make(chan os.Signal, 3) signal.Notify(sigChan, syscall.SIGTERM, os.Interrupt) <-sigChan })() @@ -262,20 +266,22 @@ func (s *aixService) Logger(errs chan<- error) (Logger, error) { } return s.SystemLogger(errs) } + func (s *aixService) SystemLogger(errs chan<- error) (Logger, error) { return newSysLogger(s.Name, errs) } var svcConfig = `#!/bin/ksh case "$1" in -start ) +start) startsrc -s {{.Name}} ;; -stop ) +stop) stopsrc -s {{.Name}} ;; -* ) - echo "Usage: $0 (start | stop)" +*) + echo "Usage: $0 {start|stop}" exit 1 + ;; esac ` diff --git a/vendor/github.com/kardianos/service/service_freebsd.go b/vendor/github.com/kardianos/service/service_freebsd.go index 66bb5746c1..752f5feb85 100644 --- a/vendor/github.com/kardianos/service/service_freebsd.go +++ b/vendor/github.com/kardianos/service/service_freebsd.go @@ -8,11 +8,13 @@ import ( "fmt" "os" "os/signal" + "path/filepath" "syscall" "text/template" ) const version = "freebsd" +const configDir = "/usr/local/etc/rc.d" type freebsdSystem struct{} @@ -88,7 +90,11 @@ func (s *freebsdService) template() *template.Template { } func (s *freebsdService) configPath() (cp string, err error) { - cp = "/usr/local/etc/rc.d/" + s.Config.Name + if oserr := os.MkdirAll(configDir, 0755); oserr != nil { + err = oserr + return + } + cp = filepath.Join(configDir, s.Config.Name) return } diff --git a/vendor/github.com/kardianos/service/service_go1.8.go b/vendor/github.com/kardianos/service/service_go1.8.go index 64bb0a9fbb..c8f45fccec 100644 --- a/vendor/github.com/kardianos/service/service_go1.8.go +++ b/vendor/github.com/kardianos/service/service_go1.8.go @@ -1,4 +1,5 @@ -//+build go1.8 +//go:build go1.8 +// +build go1.8 package service diff --git a/vendor/github.com/kardianos/service/service_linux.go b/vendor/github.com/kardianos/service/service_linux.go index 49d3faee02..edd5a0abd3 100644 --- a/vendor/github.com/kardianos/service/service_linux.go +++ b/vendor/github.com/kardianos/service/service_linux.go @@ -6,6 +6,7 @@ package service import ( "bufio" + "errors" "fmt" "io/ioutil" "os" @@ -13,6 +14,8 @@ import ( ) var cgroupFile = "/proc/1/cgroup" +var mountInfoFile = "/proc/self/mountinfo" +var dockerEnvFile = "/.dockerenv" type linuxSystemService struct { name string @@ -62,6 +65,24 @@ func init() { }, new: newOpenRCService, }, + linuxSystemService{ + name: "linux-rcs", + detect: isRCS, + interactive: func() bool { + is, _ := isInteractive() + return is + }, + new: newRCSService, + }, + linuxSystemService{ + name: "linux-procd", + detect: isProcd, + interactive: func() bool { + is, _ := isInteractive() + return is + }, + new: newProcdService, + }, linuxSystemService{ name: "unix-systemv", detect: func() bool { return true }, @@ -89,7 +110,7 @@ func binaryName(pid int) (string, error) { } func isInteractive() (bool, error) { - inContainer, err := isInContainer(cgroupFile) + inContainer, err := isInContainer() if err != nil { return false, err } @@ -109,7 +130,62 @@ func isInteractive() (bool, error) { // isInContainer checks if the service is being executed in docker or lxc // container. -func isInContainer(cgroupPath string) (bool, error) { +func isInContainer() (bool, error) { + inContainer, err := isInContainerDockerEnv(dockerEnvFile) + if err != nil { + return false, err + } + if inContainer { + return true, nil + } + + inContainer, err = isInContainerCGroup(cgroupFile) + if err != nil { + return false, err + } + if inContainer { + return true, nil + } + + return isInContainerMountInfo(mountInfoFile) +} + +func isInContainerDockerEnv(filePath string) (bool, error) { + _, err := os.Stat(filePath) + if err == nil { + return true, nil + } + if errors.Is(err, os.ErrNotExist) { + return false, nil + } + + return false, err +} + +func isInContainerMountInfo(filePath string) (bool, error) { + const maxlines = 15 // maximum lines to scan + f, err := os.Open(filePath) + if err != nil { + return false, err + } + defer f.Close() + scan := bufio.NewScanner(f) + + lines := 0 + for scan.Scan() && !(lines > maxlines) { + if strings.Contains(scan.Text(), "/docker/containers") { + return true, nil + } + lines++ + } + if err := scan.Err(); err != nil { + return false, err + } + + return false, nil +} + +func isInContainerCGroup(cgroupPath string) (bool, error) { const maxlines = 5 // maximum lines to scan f, err := os.Open(cgroupPath) diff --git a/vendor/github.com/kardianos/service/service_procd_linux.go b/vendor/github.com/kardianos/service/service_procd_linux.go new file mode 100644 index 0000000000..3213784cd1 --- /dev/null +++ b/vendor/github.com/kardianos/service/service_procd_linux.go @@ -0,0 +1,175 @@ +// Copyright 2015 Daniel Theophanes. +// Use of this source code is governed by a zlib-style +// license that can be found in the LICENSE file. + +package service + +import ( + "fmt" + "os" + "os/exec" + "strings" + "text/template" + "time" +) + +func isProcd() bool { + if _, err := exec.LookPath("procd"); err == nil { + return true + } + return false +} + +type procd struct { + *sysv + scriptPath string +} + +func newProcdService(i Interface, platform string, c *Config) (Service, error) { + sv := &sysv{ + i: i, + platform: platform, + Config: c, + } + + p := &procd{ + sysv: sv, + scriptPath: "/etc/init.d/" + sv.Name, + } + return p, nil +} + +func (p *procd) template() *template.Template { + customScript := p.Option.string(optionSysvScript, "") + + if customScript != "" { + return template.Must(template.New("").Funcs(tf).Parse(customScript)) + } + return template.Must(template.New("").Funcs(tf).Parse(procdScript)) +} + +func (p *procd) Install() error { + confPath, err := p.configPath() + if err != nil { + return err + } + _, err = os.Stat(confPath) + if err == nil { + return fmt.Errorf("init already exists: %q", confPath) + } + + f, err := os.Create(confPath) + if err != nil { + return err + } + defer f.Close() + + path, err := p.execPath() + if err != nil { + return err + } + + var to = &struct { + *Config + Path string + LogDirectory string + }{ + p.Config, + path, + p.Option.string(optionLogDirectory, defaultLogDirectory), + } + + err = p.template().Execute(f, to) + if err != nil { + return err + } + + if err = os.Chmod(confPath, 0755); err != nil { + return err + } + + if err = os.Symlink(confPath, "/etc/rc.d/S50"+p.Name); err != nil { + return err + } + if err = os.Symlink(confPath, "/etc/rc.d/K02"+p.Name); err != nil { + return err + } + + return nil +} + +func (p *procd) Uninstall() error { + if err := run(p.scriptPath, "disable"); err != nil { + return err + } + cp, err := p.configPath() + if err != nil { + return err + } + if err := os.Remove(cp); err != nil { + return err + } + return nil +} + +func (p *procd) Status() (Status, error) { + _, out, err := runWithOutput(p.scriptPath, "status") + if err != nil && !(err.Error() == "exit status 3") { + return StatusUnknown, err + } + + switch { + case strings.HasPrefix(out, "running"): + return StatusRunning, nil + case strings.HasPrefix(out, "inactive"): + return StatusStopped, nil + default: + return StatusUnknown, ErrNotInstalled + } +} + +func (p *procd) Start() error { + return run(p.scriptPath, "start") +} + +func (p *procd) Stop() error { + return run(p.scriptPath, "stop") +} + +func (p *procd) Restart() error { + err := p.Stop() + if err != nil { + return err + } + time.Sleep(50 * time.Millisecond) + return p.Start() +} + +const procdScript = `#!/bin/sh /etc/rc.common +USE_PROCD=1 +# After network starts +START=21 +# Before network stops +STOP=89 +cmd="{{.Path}}{{range .Arguments}} {{.|cmd}}{{end}}" +name="{{.Name}}" +pid_file="/var/run/${name}.pid" + +start_service() { + echo "Starting ${name}" + procd_open_instance + procd_set_param command ${cmd} + + # respawn automatically if something died, be careful if you have an alternative process supervisor + # if process exits sooner than respawn_threshold, it is considered crashed and after 5 retries the service is stopped + # if process finishes later than respawn_threshold, it is restarted unconditionally, regardless of error code + # notice that this is literal respawning of the process, no in a respawn-on-failure sense + procd_set_param respawn ${respawn_threshold:-3600} ${respawn_timeout:-5} ${respawn_retry:-5} + + procd_set_param stdout 1 # forward stdout of the command to logd + procd_set_param stderr 1 # same for stderr + procd_set_param pidfile ${pid_file} # write a pid file on instance start and remove it on stop + procd_close_instance + echo "${name} has been started" +} +` diff --git a/vendor/github.com/kardianos/service/service_rcs_linux.go b/vendor/github.com/kardianos/service/service_rcs_linux.go new file mode 100644 index 0000000000..0fca97dcdd --- /dev/null +++ b/vendor/github.com/kardianos/service/service_rcs_linux.go @@ -0,0 +1,312 @@ +// Copyright 2015 Daniel Theophanes. +// Use of this source code is governed by a zlib-style +// license that can be found in the LICENSE file. + +package service + +import ( + "bytes" + "errors" + "fmt" + "os" + "os/exec" + "os/signal" + "regexp" + "strings" + "syscall" + "text/template" + "time" +) + +type rcs struct { + i Interface + platform string + *Config +} + +func isRCS() bool { + if _, err := os.Stat("/etc/init.d/rcS"); err != nil { + return false + } + if _, err := exec.LookPath("service"); err == nil { + return false + } + if _, err := os.Stat("/etc/inittab"); err == nil { + filerc, err := os.Open("/etc/inittab") + if err != nil { + return false + } + defer filerc.Close() + + buf := new(bytes.Buffer) + buf.ReadFrom(filerc) + contents := buf.String() + + re := regexp.MustCompile(`::sysinit:.*rcS`) + matches := re.FindStringSubmatch(contents) + if len(matches) > 0 { + return true + } + return false + } + return false +} + +func newRCSService(i Interface, platform string, c *Config) (Service, error) { + s := &rcs{ + i: i, + platform: platform, + Config: c, + } + + return s, nil +} + +func (s *rcs) String() string { + if len(s.DisplayName) > 0 { + return s.DisplayName + } + return s.Name +} + +func (s *rcs) Platform() string { + return s.platform +} + +// todo +var errNoUserServiceRCS = errors.New("User services are not supported on rcS.") + +func (s *rcs) configPath() (cp string, err error) { + if s.Option.bool(optionUserService, optionUserServiceDefault) { + err = errNoUserServiceRCS + return + } + cp = "/etc/init.d/" + s.Config.Name + return +} + +func (s *rcs) template() *template.Template { + customScript := s.Option.string(optionRCSScript, "") + + if customScript != "" { + return template.Must(template.New("").Funcs(tf).Parse(customScript)) + } + return template.Must(template.New("").Funcs(tf).Parse(rcsScript)) +} + +func (s *rcs) Install() error { + confPath, err := s.configPath() + if err != nil { + return err + } + _, err = os.Stat(confPath) + if err == nil { + return fmt.Errorf("Init already exists: %s", confPath) + } + + f, err := os.Create(confPath) + if err != nil { + return err + } + defer f.Close() + + path, err := s.execPath() + if err != nil { + return err + } + + var to = &struct { + *Config + Path string + LogDirectory string + }{ + s.Config, + path, + s.Option.string(optionLogDirectory, defaultLogDirectory), + } + + err = s.template().Execute(f, to) + if err != nil { + return err + } + + if err = os.Chmod(confPath, 0755); err != nil { + return err + } + + if err = os.Symlink(confPath, "/etc/rc.d/S50"+s.Name); err != nil { + return err + } + + return nil +} + +func (s *rcs) Uninstall() error { + cp, err := s.configPath() + if err != nil { + return err + } + if err := os.Remove(cp); err != nil { + return err + } + if err := os.Remove("/etc/rc.d/S50" + s.Name); err != nil { + return err + } + return nil +} + +func (s *rcs) Logger(errs chan<- error) (Logger, error) { + if system.Interactive() { + return ConsoleLogger, nil + } + return s.SystemLogger(errs) +} +func (s *rcs) SystemLogger(errs chan<- error) (Logger, error) { + return newSysLogger(s.Name, errs) +} + +func (s *rcs) Run() (err error) { + err = s.i.Start(s) + if err != nil { + return err + } + + s.Option.funcSingle(optionRunWait, func() { + var sigChan = make(chan os.Signal, 3) + signal.Notify(sigChan, syscall.SIGTERM, os.Interrupt) + <-sigChan + })() + + return s.i.Stop(s) +} + +func (s *rcs) Status() (Status, error) { + _, out, err := runWithOutput("/etc/init.d/"+s.Name, "status") + if err != nil { + return StatusUnknown, err + } + + switch { + case strings.HasPrefix(out, "Running"): + return StatusRunning, nil + case strings.HasPrefix(out, "Stopped"): + return StatusStopped, nil + default: + return StatusUnknown, ErrNotInstalled + } +} + +func (s *rcs) Start() error { + return run("/etc/init.d/"+s.Name, "start") +} + +func (s *rcs) Stop() error { + return run("/etc/init.d/"+s.Name, "stop") +} + +func (s *rcs) Restart() error { + err := s.Stop() + if err != nil { + return err + } + time.Sleep(50 * time.Millisecond) + return s.Start() +} + +const rcsScript = `#!/bin/sh +# For RedHat and cousins: +# chkconfig: - 99 01 +# description: {{.Description}} +# processname: {{.Path}} + +### BEGIN INIT INFO +# Provides: {{.Path}} +# Required-Start: +# Required-Stop: +# Default-Start: 2 3 4 5 +# Default-Stop: 0 1 6 +# Short-Description: {{.DisplayName}} +# Description: {{.Description}} +### END INIT INFO + +cmd="{{.Path}}{{range .Arguments}} {{.|cmd}}{{end}}" + +name={{.Name}} +pid_file="/var/run/$name.pid" +stdout_log="{{.LogDirectory}}/$name.log" +stderr_log="{{.LogDirectory}}/$name.err" + +[ -e /etc/sysconfig/$name ] && . /etc/sysconfig/$name + +get_pid() { + cat "$pid_file" +} + +is_running() { + [ -f "$pid_file" ] && cat /proc/$(get_pid)/stat > /dev/null 2>&1 +} + +case "$1" in + start) + if is_running; then + echo "Already started" + else + echo "Starting $name" + {{if .WorkingDirectory}}cd '{{.WorkingDirectory}}'{{end}} + $cmd >> "$stdout_log" 2>> "$stderr_log" & + echo $! > "$pid_file" + if ! is_running; then + echo "Unable to start, see $stdout_log and $stderr_log" + exit 1 + fi + fi + ;; + stop) + if is_running; then + echo -n "Stopping $name.." + kill $(get_pid) + for i in $(seq 1 10) + do + if ! is_running; then + break + fi + echo -n "." + sleep 1 + done + echo + if is_running; then + echo "Not stopped; may still be shutting down or shutdown may have failed" + exit 1 + else + echo "Stopped" + if [ -f "$pid_file" ]; then + rm "$pid_file" + fi + fi + else + echo "Not running" + fi + ;; + restart) + $0 stop + if is_running; then + echo "Unable to stop, will not attempt to start" + exit 1 + fi + $0 start + ;; + status) + if is_running; then + echo "Running" + else + echo "Stopped" + exit 1 + fi + ;; + *) + echo "Usage: $0 {start|stop|restart|status}" + exit 1 + ;; +esac +exit 0 +` diff --git a/vendor/github.com/kardianos/service/service_systemd_linux.go b/vendor/github.com/kardianos/service/service_systemd_linux.go index 45eafe3ef0..6c21f29f17 100644 --- a/vendor/github.com/kardianos/service/service_systemd_linux.go +++ b/vendor/github.com/kardianos/service/service_systemd_linux.go @@ -9,6 +9,7 @@ import ( "errors" "fmt" "os" + "os/exec" "os/signal" "path/filepath" "regexp" @@ -19,9 +20,15 @@ import ( ) func isSystemd() bool { + if _, err := exec.LookPath("rpm-ostree"); err == nil { + return true + } if _, err := os.Stat("/run/systemd/system"); err == nil { return true } + if _, err := exec.LookPath("systemctl"); err != nil { + return false + } if _, err := os.Stat("/proc/1/comm"); err == nil { filerc, err := os.Open("/proc/1/comm") if err != nil { @@ -206,7 +213,7 @@ func (s *systemd) Uninstall() error { if err := os.Remove(cp); err != nil { return err } - return nil + return s.run("daemon-reload") } func (s *systemd) Logger(errs chan<- error) (Logger, error) { diff --git a/vendor/modules.txt b/vendor/modules.txt index 020296c073..1c446bc4df 100644 --- a/vendor/modules.txt +++ b/vendor/modules.txt @@ -66,8 +66,8 @@ github.com/jedisct1/xsecretbox # github.com/k-sone/critbitgo v1.4.0 ## explicit github.com/k-sone/critbitgo -# github.com/kardianos/service v1.2.2 -## explicit; go 1.12 +# github.com/kardianos/service v1.2.4 +## explicit; go 1.23.0 github.com/kardianos/service # github.com/lifenjoiner/dhcpdns v0.0.7 ## explicit; go 1.20