dnscrypt-proxy/vendor/github.com/kardianos/service/service_freebsd.go

221 lines
3.9 KiB
Go

// Copyright 2019 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/signal"
"syscall"
"text/template"
)
const version = "freebsd"
type freebsdSystem struct{}
func (freebsdSystem) String() string {
return version
}
func (freebsdSystem) Detect() bool {
return true
}
func (freebsdSystem) Interactive() bool {
return interactive
}
func (freebsdSystem) New(i Interface, c *Config) (Service, error) {
s := &freebsdService{
i: i,
Config: c,
}
return s, nil
}
func init() {
ChooseSystem(freebsdSystem{})
}
var interactive = false
func init() {
var err error
interactive, err = isInteractive()
if err != nil {
panic(err)
}
}
func isInteractive() (bool, error) {
return os.Getenv("IS_DAEMON") != "1", nil
}
type freebsdService struct {
i Interface
*Config
}
func (s *freebsdService) String() string {
if len(s.DisplayName) > 0 {
return s.DisplayName
}
return s.Name
}
func (s *freebsdService) Platform() string {
return version
}
func (s *freebsdService) template() *template.Template {
functions := template.FuncMap{
"bool": func(v bool) string {
if v {
return "true"
}
return "false"
},
}
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(rcScript))
}
}
func (s *freebsdService) configPath() (cp string, err error) {
cp = "/usr/local/etc/rc.d/" + s.Config.Name
return
}
func (s *freebsdService) Install() error {
path, err := s.execPath()
if err != nil {
return err
}
// write start script
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()
var to = &struct {
*Config
Path string
}{
s.Config,
path,
}
err = s.template().Execute(f, to)
if err != nil {
return err
}
if err = os.Chmod(confPath, 0755); err != nil {
return err
}
return nil
}
func (s *freebsdService) Uninstall() error {
cp, err := s.configPath()
if err != nil {
return err
}
return os.Remove(cp)
}
func (s *freebsdService) Status() (Status, error) {
cp, err := s.configPath()
if err != nil {
return StatusUnknown, err
}
if _, err = os.Stat(cp); os.IsNotExist(err) {
return StatusStopped, ErrNotInstalled
}
status, _, err := runCommand("service", false, s.Name, "status")
if status == 1 {
return StatusStopped, nil
} else if err != nil {
return StatusUnknown, err
}
return StatusRunning, nil
}
func (s *freebsdService) Start() error {
return run("service", s.Name, "start")
}
func (s *freebsdService) Stop() error {
return run("service", s.Name, "stop")
}
func (s *freebsdService) Restart() error {
return run("service", s.Name, "restart")
}
func (s *freebsdService) Run() error {
var 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 *freebsdService) Logger(errs chan<- error) (Logger, error) {
if interactive {
return ConsoleLogger, nil
}
return s.SystemLogger(errs)
}
func (s *freebsdService) SystemLogger(errs chan<- error) (Logger, error) {
return newSysLogger(s.Name, errs)
}
var rcScript = `#!/bin/sh
# PROVIDE: {{.Name}}
# REQUIRE: SERVERS
# KEYWORD: shutdown
. /etc/rc.subr
name="{{.Name}}"
{{.Name}}_env="IS_DAEMON=1"
pidfile="/var/run/${name}.pid"
command="/usr/sbin/daemon"
daemon_args="-P ${pidfile} -r -t \"${name}: daemon\"{{if .WorkingDirectory}} -c {{.WorkingDirectory}}{{end}}"
command_args="${daemon_args} {{.Path}}{{range .Arguments}} {{.}}{{end}}"
run_rc_command "$1"
`