From 880146e72f262da3a3f9959a11657e80daa8b683 Mon Sep 17 00:00:00 2001 From: Erkan Durmus Date: Mon, 3 Oct 2016 12:10:57 +0300 Subject: [PATCH 1/7] FreeBSD support --- daemon_freebsd.go | 271 ++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 271 insertions(+) create mode 100644 daemon_freebsd.go diff --git a/daemon_freebsd.go b/daemon_freebsd.go new file mode 100644 index 0000000..c057cc3 --- /dev/null +++ b/daemon_freebsd.go @@ -0,0 +1,271 @@ +package daemon + +//#include +//#include +import "C" + +import ( + "unsafe" + "fmt" + "bytes" + "path/filepath" + "os" + "os/exec" + "regexp" + "strings" + "text/template" + "io/ioutil" +) + + +// systemVRecord - standard record (struct) for linux systemV version of daemon package +type bsdRecord struct { + name string + description string + dependencies []string +} + +// Standard service path for systemV daemons +func (bsd *bsdRecord) servicePath() string { + return "/usr/local/etc/rc.d/" + bsd.name +} + +// Is a service installed +func (bsd *bsdRecord) isInstalled() bool { + + if _, err := os.Stat(bsd.servicePath()); err == nil { + return true + } + + return false +} + +// Is a service is enabled +func (bsd *bsdRecord) isEnabled() (bool, error) { + rcConf, err := os.Open("/etc/rc.conf") + if err != nil { + fmt.Println("Error opening file:", err) + return false, err + } + defer rcConf.Close() + rcData, _ := ioutil.ReadAll(rcConf) + ok, _ := regexp.Match(`^(? + exePath := make([]byte, PATH_MAX) + exeLen := C.size_t(len(exePath)) + + // Beware: sizeof(int) != sizeof(C.int) + var mib [4]C.int + // From + mib[0] = 1 // CTL_KERN + mib[1] = 14 // KERN_PROC + mib[2] = 12 // KERN_PROC_PATHNAME + mib[3] = -1 + + status, err := C.sysctl((*C.int)(unsafe.Pointer(&mib[0])), 4, unsafe.Pointer(&exePath[0]), &exeLen, nil, 0) + + if err != nil { + return "", fmt.Errorf("sysctl: %v", err) + } + + // Not sure why this might happen with err being nil, but... + if status != 0 { + return "", fmt.Errorf("sysctl returned %d", status) + } + + // Convert from null-padded []byte to a clean string. (Can't simply cast!) + exePathStringLen := bytes.Index(exePath, []byte{0}) + exePathString := string(exePath[:exePathStringLen]) + + return filepath.Clean(exePathString), nil +} + + +// Check service is running +func (bsd *bsdRecord) checkRunning() (string, bool) { + output, err := exec.Command("service", bsd.name, bsd.getCmd("status")).Output() + if err == nil { + if matched, err := regexp.MatchString(bsd.name, string(output)); err == nil && matched { + reg := regexp.MustCompile("pid ([0-9]+)") + data := reg.FindStringSubmatch(string(output)) + if len(data) > 1 { + return "Service (pid " + data[1] + ") is running...", true + } + return "Service is running...", true + } + } + + return "Service is stopped", false +} + +// Install the service +func (bsd *bsdRecord) Install(args ...string) (string, error) { + installAction := "Install " + bsd.description + ":" + + if ok, err := checkPrivileges(); !ok { + return installAction + failed, err + } + + srvPath := bsd.servicePath() + + if bsd.isInstalled() { + return installAction + failed, ErrAlreadyInstalled + } + + file, err := os.Create(srvPath) + if err != nil { + return installAction + failed, err + } + defer file.Close() + + execPatch, err := executablePath(bsd.name) + if err != nil { + return installAction + failed, err + } + + templ, err := template.New("bsdConfig").Parse(bsdConfig) + if err != nil { + return installAction + failed, err + } + + if err := templ.Execute( + file, + &struct { + Name, Description, Path, Args string + }{bsd.name, bsd.description, execPatch, strings.Join(args, " ")}, + ); err != nil { + return installAction + failed, err + } + + if err := os.Chmod(srvPath, 0755); err != nil { + return installAction + failed, err + } + + return installAction + success, nil +} + +// Remove the service +func (bsd *bsdRecord) Remove() (string, error) { + removeAction := "Removing " + bsd.description + ":" + + if ok, err := checkPrivileges(); !ok { + return removeAction + failed, err + } + + if !bsd.isInstalled() { + return removeAction + failed, ErrNotInstalled + } + + if err := os.Remove(bsd.servicePath()); err != nil { + return removeAction + failed, err + } + + return removeAction + success, nil +} + + +// Start the service +func (bsd *bsdRecord) Start() (string, error) { + startAction := "Starting " + bsd.description + ":" + + if ok, err := checkPrivileges(); !ok { + return startAction + failed, err + } + + if !bsd.isInstalled() { + return startAction + failed, ErrNotInstalled + } + + if _, ok := bsd.checkRunning(); ok { + return startAction + failed, ErrAlreadyRunning + } + + if err := exec.Command("service", bsd.name, bsd.getCmd("start")).Run(); err != nil { + return startAction + failed, err + } + + return startAction + success, nil +} + +// Stop the service +func (bsd *bsdRecord) Stop() (string, error) { + stopAction := "Stopping " + bsd.description + ":" + + if ok, err := checkPrivileges(); !ok { + return stopAction + failed, err + } + + if !bsd.isInstalled() { + return stopAction + failed, ErrNotInstalled + } + + if _, ok := bsd.checkRunning(); !ok { + return stopAction + failed, ErrAlreadyStopped + } + + if err := exec.Command("service", bsd.name, bsd.getCmd("stop")).Run(); err != nil { + return stopAction + failed, err + } + + return stopAction + success, nil +} + +// Status - Get service status +func (bsd *bsdRecord) Status() (string, error) { + + if ok, err := checkPrivileges(); !ok { + return "", err + } + + if !bsd.isInstalled() { + return "Status could not defined", ErrNotInstalled + } + + statusAction, _ := bsd.checkRunning() + + return statusAction, nil +} + +var bsdConfig = `#!/bin/sh +# +# PROVIDE: {{.Name}} +# REQUIRE: networking syslog +# KEYWORD: + +# Add the following lines to /etc/rc.conf to enable the {{.Name}}: +# +# {{.Name}}_enable="YES" +# + + +. /etc/rc.subr + +name="{{.Name}}" +rcvar="{{.Name}}_enable" +command="{{.Path}}" +pidfile="/var/run/$name.pid" + +start_cmd="/usr/sbin/daemon -p $pidfile -f $command {{.Args}} + +run_rc_command "$1" +` + From f209741755da5f7d87cc1039899ded5a5a47b422 Mon Sep 17 00:00:00 2001 From: Erkan Durmus Date: Tue, 4 Oct 2016 15:27:08 +0300 Subject: [PATCH 2/7] regexp correction --- daemon_freebsd.go | 17 +++++++++++++++-- 1 file changed, 15 insertions(+), 2 deletions(-) diff --git a/daemon_freebsd.go b/daemon_freebsd.go index c057cc3..653ea9d 100644 --- a/daemon_freebsd.go +++ b/daemon_freebsd.go @@ -49,10 +49,23 @@ func (bsd *bsdRecord) isEnabled() (bool, error) { } defer rcConf.Close() rcData, _ := ioutil.ReadAll(rcConf) - ok, _ := regexp.Match(`^(? Date: Tue, 4 Oct 2016 15:29:30 +0300 Subject: [PATCH 3/7] Update daemon_freebsd.go --- daemon_freebsd.go | 1 - 1 file changed, 1 deletion(-) diff --git a/daemon_freebsd.go b/daemon_freebsd.go index 653ea9d..6b968d3 100644 --- a/daemon_freebsd.go +++ b/daemon_freebsd.go @@ -51,7 +51,6 @@ func (bsd *bsdRecord) isEnabled() (bool, error) { rcData, _ := ioutil.ReadAll(rcConf) r, _ := regexp.Compile(`.*` + bsd.name + `_enable="YES".*`) v := string(r.Find(rcData)) - fmt.Println(v) var chrFound, sharpFound bool for _, c := range(v){ if c == '#' && !chrFound{ From 345a2f164a95484729bb4ad6f73c0cbef3561d6e Mon Sep 17 00:00:00 2001 From: Erkan Durmus Date: Tue, 4 Oct 2016 15:39:36 +0300 Subject: [PATCH 4/7] Update daemon_freebsd.go --- daemon_freebsd.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/daemon_freebsd.go b/daemon_freebsd.go index 6b968d3..61630df 100644 --- a/daemon_freebsd.go +++ b/daemon_freebsd.go @@ -277,7 +277,7 @@ command="{{.Path}}" pidfile="/var/run/$name.pid" start_cmd="/usr/sbin/daemon -p $pidfile -f $command {{.Args}} - +load_rc_config $name run_rc_command "$1" ` From fe504333d8f6caf3951c878caa33886f408faa5b Mon Sep 17 00:00:00 2001 From: Erkan Durmus Date: Tue, 4 Oct 2016 15:40:20 +0300 Subject: [PATCH 5/7] Update daemon_freebsd.go --- daemon_freebsd.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/daemon_freebsd.go b/daemon_freebsd.go index 61630df..547cb55 100644 --- a/daemon_freebsd.go +++ b/daemon_freebsd.go @@ -276,7 +276,7 @@ rcvar="{{.Name}}_enable" command="{{.Path}}" pidfile="/var/run/$name.pid" -start_cmd="/usr/sbin/daemon -p $pidfile -f $command {{.Args}} +start_cmd="/usr/sbin/daemon -p $pidfile -f $command {{.Args}}" load_rc_config $name run_rc_command "$1" ` From 678aa801ce33572e5b6f7260397cd14ba550754b Mon Sep 17 00:00:00 2001 From: Igor Dolzhikov Date: Sat, 22 Oct 2016 22:36:10 +0700 Subject: [PATCH 6/7] cotributors --- README.md | 1 + 1 file changed, 1 insertion(+) diff --git a/README.md b/README.md index 77ab517..d9f45b7 100644 --- a/README.md +++ b/README.md @@ -186,6 +186,7 @@ func main() { - [Pichu Chen](https://github.com/PichuChen) - [Eric Halpern](https://github.com/ehalpern) - [Yota](https://github.com/nus) +- [Erkan Durmus](https://github.com/derkan) All the contributors are welcome. If you would like to be the contributor please accept some rules. - The pull requests will be accepted only in "develop" branch From e2d744b403f29c124e56dbfefab7a5aebcd72a26 Mon Sep 17 00:00:00 2001 From: Igor Dolzhikov Date: Sat, 22 Oct 2016 22:36:55 +0700 Subject: [PATCH 7/7] Bumped version number to 0.7.0 --- daemon.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/daemon.go b/daemon.go index 34b5844..5bcdba8 100644 --- a/daemon.go +++ b/daemon.go @@ -3,7 +3,7 @@ // license that can be found in the LICENSE file. /* -Package daemon 0.6.2 for use with Go (golang) services. +Package daemon 0.7.0 for use with Go (golang) services. Package daemon provides primitives for daemonization of golang services. This package is not provide implementation of user daemon,