From 6c04ccb76d023a1cff867ccaf678fbc57efebd81 Mon Sep 17 00:00:00 2001 From: Julien Vehent Date: Mon, 21 Apr 2014 09:09:51 -0400 Subject: [PATCH] Add System-V support --- service_linux.go | 154 +++++++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 150 insertions(+), 4 deletions(-) diff --git a/service_linux.go b/service_linux.go index ab98131..467f10b 100644 --- a/service_linux.go +++ b/service_linux.go @@ -1,6 +1,7 @@ package service import ( + "bufio" "fmt" "log/syslog" "os" @@ -12,13 +13,17 @@ import ( ) const ( - initUpstart = initFlavor(iota) + initSystemV = initFlavor(iota) + initUpstart initSystemd ) func newService(name, displayName, description string) (Service, error) { - flavor := initUpstart - if _, err := os.Stat("/run/systemd/system"); err == nil { + flavor := initSystemV + if isUpstart() { + flavor = initUpstart + } + if isSystemd() { flavor = initSystemd } s := &linuxService{ @@ -37,6 +42,32 @@ func newService(name, displayName, description string) (Service, error) { return s, nil } +func isUpstart() bool { + f, err := os.Open("/etc/lsb-release") + if err != nil { + return false + } + defer f.Close() + r := bufio.NewReader(f) + scanner := bufio.NewScanner(r) + for scanner.Scan() { + if scanner.Text() == "DISTRIB_ID=Ubuntu" { + return true + } + } + if err := scanner.Err(); err != nil { + return false + } + return false +} + +func isSystemd() bool { + if _, err := os.Stat("/run/systemd/system"); err == nil { + return true + } + return false +} + type linuxService struct { flavor initFlavor name, displayName, description string @@ -47,6 +78,8 @@ type initFlavor uint8 func (f initFlavor) String() string { switch f { + case initSystemV: + return "System-V" case initUpstart: return "Upstart" case initSystemd: @@ -58,6 +91,8 @@ func (f initFlavor) String() string { func (f initFlavor) ConfigPath(name string) string { switch f { + case initSystemV: + return "/etc/init.d/" + name case initUpstart: return "/etc/init/" + name + ".conf" case initSystemd: @@ -70,6 +105,8 @@ func (f initFlavor) ConfigPath(name string) string { func (f initFlavor) GetTemplate() *template.Template { var templ string switch f { + case initSystemV: + templ = systemVScript case initUpstart: templ = upstartScript case initSystemd: @@ -107,11 +144,26 @@ func (s *linuxService) Install() error { } err = s.flavor.GetTemplate().Execute(f, to) - if err != nil { return err } + if s.flavor == initSystemV { + if err = os.Chmod(confPath, 0755); err != nil { + return err + } + for _, i := range [...]string{"2", "3", "4", "5"} { + if err = os.Symlink(confPath, "/etc/rc"+i+".d/S50"+s.name); err != nil { + continue + } + } + for _, i := range [...]string{"0", "1", "6"} { + if err = os.Symlink(confPath, "/etc/rc"+i+".d/K02"+s.name); err != nil { + continue + } + } + } + if s.flavor == initSystemd { return exec.Command("systemctl", "daemon-reload").Run() } @@ -165,6 +217,100 @@ func (s *linuxService) Info(format string, a ...interface{}) error { return s.logger.Info(fmt.Sprintf(format, a...)) } +const systemVScript = `#!/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: {{.Display}} +# Description: {{.Description}} +### END INIT INFO + +cmd="{{.Path}}" + +name=$(basename $0) +pid_file="/var/run/$name.pid" +stdout_log="/var/log/$name.log" +stderr_log="/var/log/$name.err" + +get_pid() { + cat "$pid_file" +} + +is_running() { + [ -f "$pid_file" ] && ps $(get_pid) > /dev/null 2>&1 +} + +case "$1" in + start) + if is_running; then + echo "Already started" + else + echo "Starting $name" + $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 {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` + const upstartScript = `# {{.Description}} description "{{.Display}}"