123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220 |
- // 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"
- `
|