service: add Config.Executable field to allow service to control other binaries.
This commit is contained in:
+334
-321
@@ -1,321 +1,334 @@
|
|||||||
// Copyright 2015 Daniel Theophanes.
|
// Copyright 2015 Daniel Theophanes.
|
||||||
// Use of this source code is governed by a zlib-style
|
// Use of this source code is governed by a zlib-style
|
||||||
// license that can be found in the LICENSE file.package service
|
// license that can be found in the LICENSE file.package service
|
||||||
|
|
||||||
// Package service provides a simple way to create a system service.
|
// Package service provides a simple way to create a system service.
|
||||||
// Currently supports Windows, Linux/(systemd | Upstart | SysV), and OSX/Launchd.
|
// Currently supports Windows, Linux/(systemd | Upstart | SysV), and OSX/Launchd.
|
||||||
//
|
//
|
||||||
// Windows controls services by setting up callbacks that is non-trivial. This
|
// Windows controls services by setting up callbacks that is non-trivial. This
|
||||||
// is very different then other systems. This package provides the same API
|
// is very different then other systems. This package provides the same API
|
||||||
// despite the substantial differences.
|
// despite the substantial differences.
|
||||||
// It also can be used to detect how a program is called, from an interactive
|
// It also can be used to detect how a program is called, from an interactive
|
||||||
// terminal or from a service manager.
|
// terminal or from a service manager.
|
||||||
//
|
//
|
||||||
// Examples in the example/ folder.
|
// Examples in the example/ folder.
|
||||||
//
|
//
|
||||||
// package main
|
// package main
|
||||||
//
|
//
|
||||||
// import (
|
// import (
|
||||||
// "log"
|
// "log"
|
||||||
//
|
//
|
||||||
// "github.com/kardianos/service"
|
// "github.com/kardianos/service"
|
||||||
// )
|
// )
|
||||||
//
|
//
|
||||||
// var logger service.Logger
|
// var logger service.Logger
|
||||||
//
|
//
|
||||||
// type program struct{}
|
// type program struct{}
|
||||||
//
|
//
|
||||||
// func (p *program) Start(s service.Service) error {
|
// func (p *program) Start(s service.Service) error {
|
||||||
// // Start should not block. Do the actual work async.
|
// // Start should not block. Do the actual work async.
|
||||||
// go p.run()
|
// go p.run()
|
||||||
// return nil
|
// return nil
|
||||||
// }
|
// }
|
||||||
// func (p *program) run() {
|
// func (p *program) run() {
|
||||||
// // Do work here
|
// // Do work here
|
||||||
// }
|
// }
|
||||||
// func (p *program) Stop(s service.Service) error {
|
// func (p *program) Stop(s service.Service) error {
|
||||||
// // Stop should not block. Return with a few seconds.
|
// // Stop should not block. Return with a few seconds.
|
||||||
// return nil
|
// return nil
|
||||||
// }
|
// }
|
||||||
//
|
//
|
||||||
// func main() {
|
// func main() {
|
||||||
// svcConfig := &service.Config{
|
// svcConfig := &service.Config{
|
||||||
// Name: "GoServiceTest",
|
// Name: "GoServiceTest",
|
||||||
// DisplayName: "Go Service Test",
|
// DisplayName: "Go Service Test",
|
||||||
// Description: "This is a test Go service.",
|
// Description: "This is a test Go service.",
|
||||||
// }
|
// }
|
||||||
//
|
//
|
||||||
// prg := &program{}
|
// prg := &program{}
|
||||||
// s, err := service.New(prg, svcConfig)
|
// s, err := service.New(prg, svcConfig)
|
||||||
// if err != nil {
|
// if err != nil {
|
||||||
// log.Fatal(err)
|
// log.Fatal(err)
|
||||||
// }
|
// }
|
||||||
// logger, err = s.Logger(nil)
|
// logger, err = s.Logger(nil)
|
||||||
// if err != nil {
|
// if err != nil {
|
||||||
// log.Fatal(err)
|
// log.Fatal(err)
|
||||||
// }
|
// }
|
||||||
// err = s.Run()
|
// err = s.Run()
|
||||||
// if err != nil {
|
// if err != nil {
|
||||||
// logger.Error(err)
|
// logger.Error(err)
|
||||||
// }
|
// }
|
||||||
// }
|
// }
|
||||||
package service // import "github.com/kardianos/service"
|
package service // import "github.com/kardianos/service"
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"errors"
|
"errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
)
|
"path/filepath"
|
||||||
|
|
||||||
// Config provides the setup for a Service. The Name field is required.
|
"github.com/kardianos/osext"
|
||||||
type Config struct {
|
)
|
||||||
Name string // Required name of the service. No spaces suggested.
|
|
||||||
DisplayName string // Display name, spaces allowed.
|
// Config provides the setup for a Service. The Name field is required.
|
||||||
Description string // Long description of service.
|
type Config struct {
|
||||||
Dependencies []string // Array of service dependencies.
|
Name string // Required name of the service. No spaces suggested.
|
||||||
|
DisplayName string // Display name, spaces allowed.
|
||||||
UserName string // Run as username.
|
Description string // Long description of service.
|
||||||
Arguments []string // Run with arguments.
|
Dependencies []string // Array of service dependencies.
|
||||||
|
|
||||||
WorkingDirectory string // Service working directory.
|
UserName string // Run as username.
|
||||||
ChRoot string
|
Arguments []string // Run with arguments.
|
||||||
UserService bool // Install as a current user service.
|
|
||||||
|
// Optional field to specify the executable for service.
|
||||||
// System specific options.
|
// If empty the current executable is used.
|
||||||
Option KeyValue
|
Executable string
|
||||||
}
|
WorkingDirectory string // Service working directory.
|
||||||
|
ChRoot string
|
||||||
var (
|
UserService bool // Install as a current user service.
|
||||||
system System
|
|
||||||
systemRegistry []System
|
// System specific options.
|
||||||
)
|
Option KeyValue
|
||||||
|
}
|
||||||
var (
|
|
||||||
// ErrNameFieldRequired is returned when Conifg.Name is empty.
|
func (c *Config) execPath() (string, error) {
|
||||||
ErrNameFieldRequired = errors.New("Config.Name field is required.")
|
if len(c.Executable) != 0 {
|
||||||
// ErrNoServiceSystemDetected is returned when no system was detected.
|
return filepath.Abs(c.Executable)
|
||||||
ErrNoServiceSystemDetected = errors.New("No service system detected.")
|
}
|
||||||
)
|
return osext.Executable()
|
||||||
|
}
|
||||||
// New creates a new service based on a service interface and configuration.
|
|
||||||
func New(i Interface, c *Config) (Service, error) {
|
var (
|
||||||
if len(c.Name) == 0 {
|
system System
|
||||||
return nil, ErrNameFieldRequired
|
systemRegistry []System
|
||||||
}
|
)
|
||||||
if system == nil {
|
|
||||||
return nil, ErrNoServiceSystemDetected
|
var (
|
||||||
}
|
// ErrNameFieldRequired is returned when Conifg.Name is empty.
|
||||||
return system.New(i, c)
|
ErrNameFieldRequired = errors.New("Config.Name field is required.")
|
||||||
}
|
// ErrNoServiceSystemDetected is returned when no system was detected.
|
||||||
|
ErrNoServiceSystemDetected = errors.New("No service system detected.")
|
||||||
// KeyValue provides a list of platform specific options. See platform docs for
|
)
|
||||||
// more details.
|
|
||||||
type KeyValue map[string]interface{}
|
// New creates a new service based on a service interface and configuration.
|
||||||
|
func New(i Interface, c *Config) (Service, error) {
|
||||||
// Bool returns the value of the given name, assuming the value is a boolean.
|
if len(c.Name) == 0 {
|
||||||
// If the value isn't found or is not of the type, the defaultValue is returned.
|
return nil, ErrNameFieldRequired
|
||||||
func (kv KeyValue) bool(name string, defaultValue bool) bool {
|
}
|
||||||
if v, found := kv[name]; found {
|
if system == nil {
|
||||||
if castValue, is := v.(bool); is {
|
return nil, ErrNoServiceSystemDetected
|
||||||
return castValue
|
}
|
||||||
}
|
return system.New(i, c)
|
||||||
}
|
}
|
||||||
return defaultValue
|
|
||||||
}
|
// KeyValue provides a list of platform specific options. See platform docs for
|
||||||
|
// more details.
|
||||||
// Int returns the value of the given name, assuming the value is an int.
|
type KeyValue map[string]interface{}
|
||||||
// If the value isn't found or is not of the type, the defaultValue is returned.
|
|
||||||
func (kv KeyValue) int(name string, defaultValue int) int {
|
// Bool returns the value of the given name, assuming the value is a boolean.
|
||||||
if v, found := kv[name]; found {
|
// If the value isn't found or is not of the type, the defaultValue is returned.
|
||||||
if castValue, is := v.(int); is {
|
func (kv KeyValue) bool(name string, defaultValue bool) bool {
|
||||||
return castValue
|
if v, found := kv[name]; found {
|
||||||
}
|
if castValue, is := v.(bool); is {
|
||||||
}
|
return castValue
|
||||||
return defaultValue
|
}
|
||||||
}
|
}
|
||||||
|
return defaultValue
|
||||||
// Int returns the value of the given name, assuming the value is a string.
|
}
|
||||||
// If the value isn't found or is not of the type, the defaultValue is returned.
|
|
||||||
func (kv KeyValue) string(name string, defaultValue string) string {
|
// Int returns the value of the given name, assuming the value is an int.
|
||||||
if v, found := kv[name]; found {
|
// If the value isn't found or is not of the type, the defaultValue is returned.
|
||||||
if castValue, is := v.(string); is {
|
func (kv KeyValue) int(name string, defaultValue int) int {
|
||||||
return castValue
|
if v, found := kv[name]; found {
|
||||||
}
|
if castValue, is := v.(int); is {
|
||||||
}
|
return castValue
|
||||||
return defaultValue
|
}
|
||||||
}
|
}
|
||||||
|
return defaultValue
|
||||||
// Int returns the value of the given name, assuming the value is a float64.
|
}
|
||||||
// If the value isn't found or is not of the type, the defaultValue is returned.
|
|
||||||
func (kv KeyValue) float64(name string, defaultValue float64) float64 {
|
// Int returns the value of the given name, assuming the value is a string.
|
||||||
if v, found := kv[name]; found {
|
// If the value isn't found or is not of the type, the defaultValue is returned.
|
||||||
if castValue, is := v.(float64); is {
|
func (kv KeyValue) string(name string, defaultValue string) string {
|
||||||
return castValue
|
if v, found := kv[name]; found {
|
||||||
}
|
if castValue, is := v.(string); is {
|
||||||
}
|
return castValue
|
||||||
return defaultValue
|
}
|
||||||
}
|
}
|
||||||
|
return defaultValue
|
||||||
// Platform returns a description of the system service.
|
}
|
||||||
func Platform() string {
|
|
||||||
if system == nil {
|
// Int returns the value of the given name, assuming the value is a float64.
|
||||||
return ""
|
// If the value isn't found or is not of the type, the defaultValue is returned.
|
||||||
}
|
func (kv KeyValue) float64(name string, defaultValue float64) float64 {
|
||||||
return system.String()
|
if v, found := kv[name]; found {
|
||||||
}
|
if castValue, is := v.(float64); is {
|
||||||
|
return castValue
|
||||||
// Interactive returns false if running under the OS service manager
|
}
|
||||||
// and true otherwise.
|
}
|
||||||
func Interactive() bool {
|
return defaultValue
|
||||||
if system == nil {
|
}
|
||||||
return true
|
|
||||||
}
|
// Platform returns a description of the system service.
|
||||||
return system.Interactive()
|
func Platform() string {
|
||||||
}
|
if system == nil {
|
||||||
|
return ""
|
||||||
func newSystem() System {
|
}
|
||||||
for _, choice := range systemRegistry {
|
return system.String()
|
||||||
if choice.Detect() == false {
|
}
|
||||||
continue
|
|
||||||
}
|
// Interactive returns false if running under the OS service manager
|
||||||
return choice
|
// and true otherwise.
|
||||||
}
|
func Interactive() bool {
|
||||||
return nil
|
if system == nil {
|
||||||
}
|
return true
|
||||||
|
}
|
||||||
// ChooseSystem chooses a system from the given system services.
|
return system.Interactive()
|
||||||
// SystemServices are considered in the order they are suggested.
|
}
|
||||||
// Calling this may change what Interactive and Platform return.
|
|
||||||
func ChooseSystem(a ...System) {
|
func newSystem() System {
|
||||||
systemRegistry = a
|
for _, choice := range systemRegistry {
|
||||||
system = newSystem()
|
if choice.Detect() == false {
|
||||||
}
|
continue
|
||||||
|
}
|
||||||
// ChosenSystem returns the system that service will use.
|
return choice
|
||||||
func ChosenSystem() System {
|
}
|
||||||
return system
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// AvailableSystems returns the list of system services considered
|
// ChooseSystem chooses a system from the given system services.
|
||||||
// when choosing the system service.
|
// SystemServices are considered in the order they are suggested.
|
||||||
func AvailableSystems() []System {
|
// Calling this may change what Interactive and Platform return.
|
||||||
return systemRegistry
|
func ChooseSystem(a ...System) {
|
||||||
}
|
systemRegistry = a
|
||||||
|
system = newSystem()
|
||||||
// System represents the service manager that is available.
|
}
|
||||||
type System interface {
|
|
||||||
// String returns a description of the system.
|
// ChosenSystem returns the system that service will use.
|
||||||
String() string
|
func ChosenSystem() System {
|
||||||
|
return system
|
||||||
// Detect returns true if the system is available to use.
|
}
|
||||||
Detect() bool
|
|
||||||
|
// AvailableSystems returns the list of system services considered
|
||||||
// Interactive returns false if running under the system service manager
|
// when choosing the system service.
|
||||||
// and true otherwise.
|
func AvailableSystems() []System {
|
||||||
Interactive() bool
|
return systemRegistry
|
||||||
|
}
|
||||||
// New creates a new service for this system.
|
|
||||||
New(i Interface, c *Config) (Service, error)
|
// System represents the service manager that is available.
|
||||||
}
|
type System interface {
|
||||||
|
// String returns a description of the system.
|
||||||
// Interface represents the service interface for a program. Start runs before
|
String() string
|
||||||
// the hosting process is granted control and Stop runs when control is returned.
|
|
||||||
//
|
// Detect returns true if the system is available to use.
|
||||||
// 1. OS service manager executes user program.
|
Detect() bool
|
||||||
// 2. User program sees it is executed from a service manager (IsInteractive is false).
|
|
||||||
// 3. User program calls Service.Run() which blocks.
|
// Interactive returns false if running under the system service manager
|
||||||
// 4. Interface.Start() is called and quickly returns.
|
// and true otherwise.
|
||||||
// 5. User program runs.
|
Interactive() bool
|
||||||
// 6. OS service manager signals the user program to stop.
|
|
||||||
// 7. Interface.Stop() is called and quickly returns.
|
// New creates a new service for this system.
|
||||||
// - For a successful exit, os.Exit should not be called in Interface.Stop().
|
New(i Interface, c *Config) (Service, error)
|
||||||
// 8. Service.Run returns.
|
}
|
||||||
// 9. User program should quickly exit.
|
|
||||||
type Interface interface {
|
// Interface represents the service interface for a program. Start runs before
|
||||||
// Start provides a place to initiate the service. The service doesn't not
|
// the hosting process is granted control and Stop runs when control is returned.
|
||||||
// signal a completed start until after this function returns, so the
|
//
|
||||||
// Start function must not take more then a few seconds at most.
|
// 1. OS service manager executes user program.
|
||||||
Start(s Service) error
|
// 2. User program sees it is executed from a service manager (IsInteractive is false).
|
||||||
|
// 3. User program calls Service.Run() which blocks.
|
||||||
// Stop provides a place to clean up program execution before it is terminated.
|
// 4. Interface.Start() is called and quickly returns.
|
||||||
// It should not take more then a few seconds to execute.
|
// 5. User program runs.
|
||||||
// Stop should not call os.Exit directly in the function.
|
// 6. OS service manager signals the user program to stop.
|
||||||
Stop(s Service) error
|
// 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.
|
||||||
// TODO: Add Configure to Service interface.
|
// 9. User program should quickly exit.
|
||||||
|
type Interface interface {
|
||||||
// Service represents a service that can be run or controlled.
|
// Start provides a place to initiate the service. The service doesn't not
|
||||||
type Service interface {
|
// signal a completed start until after this function returns, so the
|
||||||
// Run should be called shortly after the program entry point.
|
// Start function must not take more then a few seconds at most.
|
||||||
// After Interface.Stop has finished running, Run will stop blocking.
|
Start(s Service) error
|
||||||
// After Run stops blocking, the program must exit shortly after.
|
|
||||||
Run() error
|
// Stop provides a place to clean up program execution before it is terminated.
|
||||||
|
// It should not take more then a few seconds to execute.
|
||||||
// Start signals to the OS service manager the given service should start.
|
// Stop should not call os.Exit directly in the function.
|
||||||
Start() error
|
Stop(s Service) error
|
||||||
|
}
|
||||||
// Stop signals to the OS service manager the given service should stop.
|
|
||||||
Stop() error
|
// TODO: Add Configure to Service interface.
|
||||||
|
|
||||||
// Restart signals to the OS service manager the given service should stop then start.
|
// Service represents a service that can be run or controlled.
|
||||||
Restart() error
|
type Service interface {
|
||||||
|
// Run should be called shortly after the program entry point.
|
||||||
// Install setups up the given service in the OS service manager. This may require
|
// After Interface.Stop has finished running, Run will stop blocking.
|
||||||
// greater rights. Will return an error if it is already installed.
|
// After Run stops blocking, the program must exit shortly after.
|
||||||
Install() error
|
Run() error
|
||||||
|
|
||||||
// Uninstall removes the given service from the OS service manager. This may require
|
// Start signals to the OS service manager the given service should start.
|
||||||
// greater rights. Will return an error if the service is not present.
|
Start() error
|
||||||
Uninstall() error
|
|
||||||
|
// Stop signals to the OS service manager the given service should stop.
|
||||||
// Opens and returns a system logger. If the user program is running
|
Stop() error
|
||||||
// interactively rather then as a service, the returned logger will write to
|
|
||||||
// os.Stderr. If errs is non-nil errors will be sent on errs as well as
|
// Restart signals to the OS service manager the given service should stop then start.
|
||||||
// returned from Logger's functions.
|
Restart() error
|
||||||
Logger(errs chan<- error) (Logger, error)
|
|
||||||
|
// Install setups up the given service in the OS service manager. This may require
|
||||||
// SystemLogger opens and returns a system logger. If errs is non-nil errors
|
// greater rights. Will return an error if it is already installed.
|
||||||
// will be sent on errs as well as returned from Logger's functions.
|
Install() error
|
||||||
SystemLogger(errs chan<- error) (Logger, error)
|
|
||||||
|
// Uninstall removes the given service from the OS service manager. This may require
|
||||||
// String displays the name of the service. The display name if present,
|
// greater rights. Will return an error if the service is not present.
|
||||||
// otherwise the name.
|
Uninstall() error
|
||||||
String() string
|
|
||||||
}
|
// Opens and returns a system logger. If the user program is running
|
||||||
|
// interactively rather then as a service, the returned logger will write to
|
||||||
// ControlAction list valid string texts to use in Control.
|
// os.Stderr. If errs is non-nil errors will be sent on errs as well as
|
||||||
var ControlAction = [5]string{"start", "stop", "restart", "install", "uninstall"}
|
// returned from Logger's functions.
|
||||||
|
Logger(errs chan<- error) (Logger, error)
|
||||||
// Control issues control functions to the service from a given action string.
|
|
||||||
func Control(s Service, action string) error {
|
// SystemLogger opens and returns a system logger. If errs is non-nil errors
|
||||||
var err error
|
// will be sent on errs as well as returned from Logger's functions.
|
||||||
switch action {
|
SystemLogger(errs chan<- error) (Logger, error)
|
||||||
case ControlAction[0]:
|
|
||||||
err = s.Start()
|
// String displays the name of the service. The display name if present,
|
||||||
case ControlAction[1]:
|
// otherwise the name.
|
||||||
err = s.Stop()
|
String() string
|
||||||
case ControlAction[2]:
|
}
|
||||||
err = s.Restart()
|
|
||||||
case ControlAction[3]:
|
// ControlAction list valid string texts to use in Control.
|
||||||
err = s.Install()
|
var ControlAction = [5]string{"start", "stop", "restart", "install", "uninstall"}
|
||||||
case ControlAction[4]:
|
|
||||||
err = s.Uninstall()
|
// Control issues control functions to the service from a given action string.
|
||||||
default:
|
func Control(s Service, action string) error {
|
||||||
err = fmt.Errorf("Unknown action %s", action)
|
var err error
|
||||||
}
|
switch action {
|
||||||
if err != nil {
|
case ControlAction[0]:
|
||||||
return fmt.Errorf("Failed to %s %v: %v", action, s, err)
|
err = s.Start()
|
||||||
}
|
case ControlAction[1]:
|
||||||
return nil
|
err = s.Stop()
|
||||||
}
|
case ControlAction[2]:
|
||||||
|
err = s.Restart()
|
||||||
// Logger writes to the system log.
|
case ControlAction[3]:
|
||||||
type Logger interface {
|
err = s.Install()
|
||||||
Error(v ...interface{}) error
|
case ControlAction[4]:
|
||||||
Warning(v ...interface{}) error
|
err = s.Uninstall()
|
||||||
Info(v ...interface{}) error
|
default:
|
||||||
|
err = fmt.Errorf("Unknown action %s", action)
|
||||||
Errorf(format string, a ...interface{}) error
|
}
|
||||||
Warningf(format string, a ...interface{}) error
|
if err != nil {
|
||||||
Infof(format string, a ...interface{}) error
|
return fmt.Errorf("Failed to %s %v: %v", action, s, err)
|
||||||
}
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// Logger writes to the system log.
|
||||||
|
type Logger interface {
|
||||||
|
Error(v ...interface{}) error
|
||||||
|
Warning(v ...interface{}) error
|
||||||
|
Info(v ...interface{}) error
|
||||||
|
|
||||||
|
Errorf(format string, a ...interface{}) error
|
||||||
|
Warningf(format string, a ...interface{}) error
|
||||||
|
Infof(format string, a ...interface{}) error
|
||||||
|
}
|
||||||
|
|||||||
+1
-3
@@ -12,8 +12,6 @@ import (
|
|||||||
"syscall"
|
"syscall"
|
||||||
"text/template"
|
"text/template"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/kardianos/osext"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
const maxPathSize = 32 * 1024
|
const maxPathSize = 32 * 1024
|
||||||
@@ -98,7 +96,7 @@ func (s *darwinLaunchdService) Install() error {
|
|||||||
}
|
}
|
||||||
defer f.Close()
|
defer f.Close()
|
||||||
|
|
||||||
path, err := osext.Executable()
|
path, err := s.execPath()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -12,8 +12,6 @@ import (
|
|||||||
"syscall"
|
"syscall"
|
||||||
"text/template"
|
"text/template"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/kardianos/osext"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
func isSystemd() bool {
|
func isSystemd() bool {
|
||||||
@@ -75,7 +73,7 @@ func (s *systemd) Install() error {
|
|||||||
}
|
}
|
||||||
defer f.Close()
|
defer f.Close()
|
||||||
|
|
||||||
path, err := osext.Executable()
|
path, err := s.execPath()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -12,8 +12,6 @@ import (
|
|||||||
"syscall"
|
"syscall"
|
||||||
"text/template"
|
"text/template"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/kardianos/osext"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
type sysv struct {
|
type sysv struct {
|
||||||
@@ -67,7 +65,7 @@ func (s *sysv) Install() error {
|
|||||||
}
|
}
|
||||||
defer f.Close()
|
defer f.Close()
|
||||||
|
|
||||||
path, err := osext.Executable()
|
path, err := s.execPath()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -8,12 +8,10 @@ import (
|
|||||||
"errors"
|
"errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
"os"
|
"os"
|
||||||
|
"os/exec"
|
||||||
"os/signal"
|
"os/signal"
|
||||||
"syscall"
|
|
||||||
"text/template"
|
"text/template"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/kardianos/osext"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
func isUpstart() bool {
|
func isUpstart() bool {
|
||||||
@@ -77,7 +75,7 @@ func (s *upstart) Install() error {
|
|||||||
}
|
}
|
||||||
defer f.Close()
|
defer f.Close()
|
||||||
|
|
||||||
path, err := osext.Executable()
|
path, err := s.execPath()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
@@ -122,7 +120,7 @@ func (s *upstart) Run() (err error) {
|
|||||||
|
|
||||||
sigChan := make(chan os.Signal, 3)
|
sigChan := make(chan os.Signal, 3)
|
||||||
|
|
||||||
signal.Notify(sigChan, syscall.SIGTERM, os.Interrupt)
|
signal.Notify(sigChan, os.Interrupt, os.Kill)
|
||||||
|
|
||||||
<-sigChan
|
<-sigChan
|
||||||
|
|
||||||
@@ -130,11 +128,11 @@ func (s *upstart) Run() (err error) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (s *upstart) Start() error {
|
func (s *upstart) Start() error {
|
||||||
return run("initctl", "start", s.Name)
|
return exec.Command("initctl", "start", s.Name).Run()
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *upstart) Stop() error {
|
func (s *upstart) Stop() error {
|
||||||
return run("initctl", "stop", s.Name)
|
return exec.Command("initctl", "stop", s.Name).Run()
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *upstart) Restart() error {
|
func (s *upstart) Restart() error {
|
||||||
|
|||||||
+2
-2
@@ -16,7 +16,6 @@ import (
|
|||||||
"code.google.com/p/winsvc/eventlog"
|
"code.google.com/p/winsvc/eventlog"
|
||||||
"code.google.com/p/winsvc/mgr"
|
"code.google.com/p/winsvc/mgr"
|
||||||
"code.google.com/p/winsvc/svc"
|
"code.google.com/p/winsvc/svc"
|
||||||
"github.com/kardianos/osext"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
const version = "Windows Service"
|
const version = "Windows Service"
|
||||||
@@ -165,10 +164,11 @@ loop:
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (ws *windowsService) Install() error {
|
func (ws *windowsService) Install() error {
|
||||||
exepath, err := osext.Executable()
|
exepath, err := ws.execPath()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
binPath := &bytes.Buffer{}
|
binPath := &bytes.Buffer{}
|
||||||
// Quote exe path in case it contains a string.
|
// Quote exe path in case it contains a string.
|
||||||
binPath.WriteRune('"')
|
binPath.WriteRune('"')
|
||||||
|
|||||||
Reference in New Issue
Block a user