service_sysv_linux.go 4.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252
  1. // Copyright 2015 Daniel Theophanes.
  2. // Use of this source code is governed by a zlib-style
  3. // license that can be found in the LICENSE file.
  4. package service
  5. import (
  6. "errors"
  7. "fmt"
  8. "os"
  9. "os/signal"
  10. "syscall"
  11. "text/template"
  12. "time"
  13. )
  14. type sysv struct {
  15. i Interface
  16. *Config
  17. }
  18. func newSystemVService(i Interface, c *Config) (Service, error) {
  19. s := &sysv{
  20. i: i,
  21. Config: c,
  22. }
  23. return s, nil
  24. }
  25. func (s *sysv) String() string {
  26. if len(s.DisplayName) > 0 {
  27. return s.DisplayName
  28. }
  29. return s.Name
  30. }
  31. var errNoUserServiceSystemV = errors.New("User services are not supported on SystemV.")
  32. func (s *sysv) configPath() (cp string, err error) {
  33. if s.Option.bool(optionUserService, optionUserServiceDefault) {
  34. err = errNoUserServiceSystemV
  35. return
  36. }
  37. cp = "/etc/init.d/" + s.Config.Name
  38. return
  39. }
  40. func (s *sysv) template() *template.Template {
  41. return template.Must(template.New("").Funcs(tf).Parse(sysvScript))
  42. }
  43. func (s *sysv) Install() error {
  44. confPath, err := s.configPath()
  45. if err != nil {
  46. return err
  47. }
  48. _, err = os.Stat(confPath)
  49. if err == nil {
  50. return fmt.Errorf("Init already exists: %s", confPath)
  51. }
  52. f, err := os.Create(confPath)
  53. if err != nil {
  54. return err
  55. }
  56. defer f.Close()
  57. path, err := s.execPath()
  58. if err != nil {
  59. return err
  60. }
  61. var to = &struct {
  62. *Config
  63. Path string
  64. }{
  65. s.Config,
  66. path,
  67. }
  68. err = s.template().Execute(f, to)
  69. if err != nil {
  70. return err
  71. }
  72. if err = os.Chmod(confPath, 0755); err != nil {
  73. return err
  74. }
  75. for _, i := range [...]string{"2", "3", "4", "5"} {
  76. if err = os.Symlink(confPath, "/etc/rc"+i+".d/S50"+s.Name); err != nil {
  77. continue
  78. }
  79. }
  80. for _, i := range [...]string{"0", "1", "6"} {
  81. if err = os.Symlink(confPath, "/etc/rc"+i+".d/K02"+s.Name); err != nil {
  82. continue
  83. }
  84. }
  85. return nil
  86. }
  87. func (s *sysv) Uninstall() error {
  88. cp, err := s.configPath()
  89. if err != nil {
  90. return err
  91. }
  92. if err := os.Remove(cp); err != nil {
  93. return err
  94. }
  95. return nil
  96. }
  97. func (s *sysv) Logger(errs chan<- error) (Logger, error) {
  98. if system.Interactive() {
  99. return ConsoleLogger, nil
  100. }
  101. return s.SystemLogger(errs)
  102. }
  103. func (s *sysv) SystemLogger(errs chan<- error) (Logger, error) {
  104. return newSysLogger(s.Name, errs)
  105. }
  106. func (s *sysv) Run() (err error) {
  107. err = s.i.Start(s)
  108. if err != nil {
  109. return err
  110. }
  111. s.Option.funcSingle(optionRunWait, func() {
  112. var sigChan = make(chan os.Signal, 3)
  113. signal.Notify(sigChan, syscall.SIGTERM, os.Interrupt)
  114. <-sigChan
  115. })()
  116. return s.i.Stop(s)
  117. }
  118. func (s *sysv) Start() error {
  119. return run("service", s.Name, "start")
  120. }
  121. func (s *sysv) Stop() error {
  122. return run("service", s.Name, "stop")
  123. }
  124. func (s *sysv) Restart() error {
  125. err := s.Stop()
  126. if err != nil {
  127. return err
  128. }
  129. time.Sleep(50 * time.Millisecond)
  130. return s.Start()
  131. }
  132. const sysvScript = `#!/bin/sh
  133. # For RedHat and cousins:
  134. # chkconfig: - 99 01
  135. # description: {{.Description}}
  136. # processname: {{.Path}}
  137. ### BEGIN INIT INFO
  138. # Provides: {{.Path}}
  139. # Required-Start:
  140. # Required-Stop:
  141. # Default-Start: 2 3 4 5
  142. # Default-Stop: 0 1 6
  143. # Short-Description: {{.DisplayName}}
  144. # Description: {{.Description}}
  145. ### END INIT INFO
  146. cmd="{{.Path}}{{range .Arguments}} {{.|cmd}}{{end}}"
  147. name=$(basename $(readlink -f $0))
  148. pid_file="/var/run/$name.pid"
  149. stdout_log="/var/log/$name.log"
  150. stderr_log="/var/log/$name.err"
  151. [ -e /etc/sysconfig/$name ] && . /etc/sysconfig/$name
  152. get_pid() {
  153. cat "$pid_file"
  154. }
  155. is_running() {
  156. [ -f "$pid_file" ] && ps $(get_pid) > /dev/null 2>&1
  157. }
  158. case "$1" in
  159. start)
  160. if is_running; then
  161. echo "Already started"
  162. else
  163. echo "Starting $name"
  164. {{if .WorkingDirectory}}cd '{{.WorkingDirectory}}'{{end}}
  165. $cmd >> "$stdout_log" 2>> "$stderr_log" &
  166. echo $! > "$pid_file"
  167. if ! is_running; then
  168. echo "Unable to start, see $stdout_log and $stderr_log"
  169. exit 1
  170. fi
  171. fi
  172. ;;
  173. stop)
  174. if is_running; then
  175. echo -n "Stopping $name.."
  176. kill $(get_pid)
  177. for i in $(seq 1 10)
  178. do
  179. if ! is_running; then
  180. break
  181. fi
  182. echo -n "."
  183. sleep 1
  184. done
  185. echo
  186. if is_running; then
  187. echo "Not stopped; may still be shutting down or shutdown may have failed"
  188. exit 1
  189. else
  190. echo "Stopped"
  191. if [ -f "$pid_file" ]; then
  192. rm "$pid_file"
  193. fi
  194. fi
  195. else
  196. echo "Not running"
  197. fi
  198. ;;
  199. restart)
  200. $0 stop
  201. if is_running; then
  202. echo "Unable to stop, will not attempt to start"
  203. exit 1
  204. fi
  205. $0 start
  206. ;;
  207. status)
  208. if is_running; then
  209. echo "Running"
  210. else
  211. echo "Stopped"
  212. exit 1
  213. fi
  214. ;;
  215. *)
  216. echo "Usage: $0 {start|stop|restart|status}"
  217. exit 1
  218. ;;
  219. esac
  220. exit 0
  221. `