From ef24fb16458a3adb3bde5e3718a37fe9e487b810 Mon Sep 17 00:00:00 2001 From: Igor Dolzhikov Date: Fri, 11 Mar 2016 13:43:06 +0700 Subject: [PATCH 1/6] Fix #16 by call "id -g" instead of user.Current & user.Gid --- helper.go | 31 +++++++++++++++++++++++-------- 1 file changed, 23 insertions(+), 8 deletions(-) diff --git a/helper.go b/helper.go index 74c6862..7a83f8b 100644 --- a/helper.go +++ b/helper.go @@ -1,16 +1,26 @@ package daemon import ( + "errors" "os" "os/exec" - "os/user" + "strconv" + "strings" ) // Service constants const ( - rootPrivileges = "You must have root user privileges. Possibly using 'sudo' command should help" - success = "\t\t\t\t\t[ \033[32mOK\033[0m ]" // Show colored "OK" - failed = "\t\t\t\t\t[\033[31mFAILED\033[0m]" // Show colored "FAILED" + success = "\t\t\t\t\t[ \033[32mOK\033[0m ]" // Show colored "OK" + failed = "\t\t\t\t\t[\033[31mFAILED\033[0m]" // Show colored "FAILED" +) + +var ( + ErrUnsupportedSystem = errors.New("Unsupported system") + ErrRootPriveleges = errors.New("You must have root user privileges. Possibly using 'sudo' command should help") + ErrAlreadyInstalled = errors.New("Service has already been installed") + ErrNotInstalled = errors.New("Service is not installed") + ErrAlreadyStopped = errors.New("Service has already been stopped") + ErrAlreadyRunning = errors.New("Service is alredy running") ) // Lookup path for executable file @@ -26,10 +36,15 @@ func executablePath(name string) (string, error) { } // Check root rights to use system service -func checkPrivileges() bool { +func checkPrivileges() (bool, error) { - if user, err := user.Current(); err == nil && user.Gid == "0" { - return true + if output, err := exec.Command("id", "-g").Output(); err == nil { + if gid, parseErr := strconv.ParseUint(strings.TrimSpace(string(output)), 10, 32); parseErr == nil { + if gid == 0 { + return true, nil + } + return false, ErrRootPriveleges + } } - return false + return false, ErrUnsupportedSystem } From c11b24c0060372157b4f2bb551e23577f44a9f29 Mon Sep 17 00:00:00 2001 From: Igor Dolzhikov Date: Fri, 11 Mar 2016 13:44:42 +0700 Subject: [PATCH 2/6] changed checkPrivileges() format, errors, return values --- daemon_darwin.go | 53 ++++++++++++++++++++--------------------- daemon_linux_systemd.go | 53 ++++++++++++++++++++--------------------- daemon_linux_systemv.go | 53 ++++++++++++++++++++--------------------- 3 files changed, 78 insertions(+), 81 deletions(-) diff --git a/daemon_darwin.go b/daemon_darwin.go index 99c690c..320fe1a 100644 --- a/daemon_darwin.go +++ b/daemon_darwin.go @@ -6,7 +6,6 @@ package daemon import ( - "errors" "os" "os/exec" "path/filepath" @@ -31,8 +30,8 @@ func (darwin *darwinRecord) servicePath() string { return "/Library/LaunchDaemons/" + darwin.name + ".plist" } -// Check service is installed -func (darwin *darwinRecord) checkInstalled() bool { +// Is a service installed +func (darwin *darwinRecord) isInstalled() bool { if _, err := os.Stat(darwin.servicePath()); err == nil { return true @@ -67,14 +66,14 @@ func (darwin *darwinRecord) checkRunning() (string, bool) { func (darwin *darwinRecord) Install() (string, error) { installAction := "Install " + darwin.description + ":" - if checkPrivileges() == false { - return installAction + failed, errors.New(rootPrivileges) + if ok, err := checkPrivileges(); !ok { + return installAction + failed, err } srvPath := darwin.servicePath() - if darwin.checkInstalled() == true { - return installAction + failed, errors.New(darwin.description + " already installed") + if darwin.isInstalled() { + return installAction + failed, ErrAlreadyInstalled } file, err := os.Create(srvPath) @@ -109,12 +108,12 @@ func (darwin *darwinRecord) Install() (string, error) { func (darwin *darwinRecord) Remove() (string, error) { removeAction := "Removing " + darwin.description + ":" - if checkPrivileges() == false { - return removeAction + failed, errors.New(rootPrivileges) + if ok, err := checkPrivileges(); !ok { + return removeAction + failed, err } - if darwin.checkInstalled() == false { - return removeAction + failed, errors.New(darwin.description + " is not installed") + if !darwin.isInstalled() { + return removeAction + failed, ErrNotInstalled } if err := os.Remove(darwin.servicePath()); err != nil { @@ -128,16 +127,16 @@ func (darwin *darwinRecord) Remove() (string, error) { func (darwin *darwinRecord) Start() (string, error) { startAction := "Starting " + darwin.description + ":" - if checkPrivileges() == false { - return startAction + failed, errors.New(rootPrivileges) + if ok, err := checkPrivileges(); !ok { + return startAction + failed, err } - if darwin.checkInstalled() == false { - return startAction + failed, errors.New(darwin.description + " is not installed") + if !darwin.isInstalled() { + return startAction + failed, ErrNotInstalled } - if _, status := darwin.checkRunning(); status == true { - return startAction + failed, errors.New("service already running") + if _, ok := darwin.checkRunning(); ok { + return startAction + failed, ErrAlreadyRunning } if err := exec.Command("launchctl", "load", darwin.servicePath()).Run(); err != nil { @@ -151,16 +150,16 @@ func (darwin *darwinRecord) Start() (string, error) { func (darwin *darwinRecord) Stop() (string, error) { stopAction := "Stopping " + darwin.description + ":" - if checkPrivileges() == false { - return stopAction + failed, errors.New(rootPrivileges) + if ok, err := checkPrivileges(); !ok { + return stopAction + failed, err } - if darwin.checkInstalled() == false { - return stopAction + failed, errors.New(darwin.description + " is not installed") + if !darwin.isInstalled() { + return stopAction + failed, ErrNotInstalled } - if _, status := darwin.checkRunning(); status == false { - return stopAction + failed, errors.New("service already stopped") + if _, ok := darwin.checkRunning(); !ok { + return stopAction + failed, ErrAlreadyStopped } if err := exec.Command("launchctl", "unload", darwin.servicePath()).Run(); err != nil { @@ -173,12 +172,12 @@ func (darwin *darwinRecord) Stop() (string, error) { // Status - Get service status func (darwin *darwinRecord) Status() (string, error) { - if checkPrivileges() == false { - return "", errors.New(rootPrivileges) + if ok, err := checkPrivileges(); !ok { + return "", err } - if darwin.checkInstalled() == false { - return "Status could not defined", errors.New(darwin.description + " is not installed") + if !darwin.isInstalled() { + return "Status could not defined", ErrNotInstalled } statusAction, _ := darwin.checkRunning() diff --git a/daemon_linux_systemd.go b/daemon_linux_systemd.go index 7968973..c4e915a 100644 --- a/daemon_linux_systemd.go +++ b/daemon_linux_systemd.go @@ -5,7 +5,6 @@ package daemon import ( - "errors" "os" "os/exec" "regexp" @@ -25,8 +24,8 @@ func (linux *systemDRecord) servicePath() string { return "/etc/systemd/system/" + linux.name + ".service" } -// Check service is installed -func (linux *systemDRecord) checkInstalled() bool { +// Is a service installed +func (linux *systemDRecord) isInstalled() bool { if _, err := os.Stat(linux.servicePath()); err == nil { return true @@ -56,14 +55,14 @@ func (linux *systemDRecord) checkRunning() (string, bool) { func (linux *systemDRecord) Install() (string, error) { installAction := "Install " + linux.description + ":" - if checkPrivileges() == false { - return installAction + failed, errors.New(rootPrivileges) + if ok, err := checkPrivileges(); !ok { + return installAction + failed, err } srvPath := linux.servicePath() - if linux.checkInstalled() == true { - return installAction + failed, errors.New(linux.description + " already installed") + if linux.isInstalled() { + return installAction + failed, ErrAlreadyInstalled } file, err := os.Create(srvPath) @@ -106,12 +105,12 @@ func (linux *systemDRecord) Install() (string, error) { func (linux *systemDRecord) Remove() (string, error) { removeAction := "Removing " + linux.description + ":" - if checkPrivileges() == false { - return removeAction + failed, errors.New(rootPrivileges) + if ok, err := checkPrivileges(); !ok { + return removeAction + failed, err } - if linux.checkInstalled() == false { - return removeAction + failed, errors.New(linux.description + " is not installed") + if !linux.isInstalled() { + return removeAction + failed, ErrNotInstalled } if err := exec.Command("systemctl", "disable", linux.name+".service").Run(); err != nil { @@ -129,16 +128,16 @@ func (linux *systemDRecord) Remove() (string, error) { func (linux *systemDRecord) Start() (string, error) { startAction := "Starting " + linux.description + ":" - if checkPrivileges() == false { - return startAction + failed, errors.New(rootPrivileges) + if ok, err := checkPrivileges(); !ok { + return startAction + failed, err } - if linux.checkInstalled() == false { - return startAction + failed, errors.New(linux.description + " is not installed") + if !linux.isInstalled() { + return startAction + failed, ErrNotInstalled } - if _, status := linux.checkRunning(); status == true { - return startAction + failed, errors.New("service already running") + if _, ok := linux.checkRunning(); ok { + return startAction + failed, ErrAlreadyRunning } if err := exec.Command("systemctl", "start", linux.name+".service").Run(); err != nil { @@ -152,16 +151,16 @@ func (linux *systemDRecord) Start() (string, error) { func (linux *systemDRecord) Stop() (string, error) { stopAction := "Stopping " + linux.description + ":" - if checkPrivileges() == false { - return stopAction + failed, errors.New(rootPrivileges) + if ok, err := checkPrivileges(); !ok { + return stopAction + failed, err } - if linux.checkInstalled() == false { - return stopAction + failed, errors.New(linux.description + " is not installed") + if !linux.isInstalled() { + return stopAction + failed, ErrNotInstalled } - if _, status := linux.checkRunning(); status == false { - return stopAction + failed, errors.New("service already stopped") + if _, ok := linux.checkRunning(); !ok { + return stopAction + failed, ErrAlreadyStopped } if err := exec.Command("systemctl", "stop", linux.name+".service").Run(); err != nil { @@ -174,12 +173,12 @@ func (linux *systemDRecord) Stop() (string, error) { // Status - Get service status func (linux *systemDRecord) Status() (string, error) { - if checkPrivileges() == false { - return "", errors.New(rootPrivileges) + if ok, err := checkPrivileges(); !ok { + return "", err } - if linux.checkInstalled() == false { - return "Status could not defined", errors.New(linux.description + " is not installed") + if !linux.isInstalled() { + return "Status could not defined", ErrNotInstalled } statusAction, _ := linux.checkRunning() diff --git a/daemon_linux_systemv.go b/daemon_linux_systemv.go index c8a8f82..1cde022 100644 --- a/daemon_linux_systemv.go +++ b/daemon_linux_systemv.go @@ -5,7 +5,6 @@ package daemon import ( - "errors" "os" "os/exec" "regexp" @@ -24,8 +23,8 @@ func (linux *systemVRecord) servicePath() string { return "/etc/init.d/" + linux.name } -// Check service is installed -func (linux *systemVRecord) checkInstalled() bool { +// Is a service installed +func (linux *systemVRecord) isInstalled() bool { if _, err := os.Stat(linux.servicePath()); err == nil { return true @@ -55,14 +54,14 @@ func (linux *systemVRecord) checkRunning() (string, bool) { func (linux *systemVRecord) Install() (string, error) { installAction := "Install " + linux.description + ":" - if checkPrivileges() == false { - return installAction + failed, errors.New(rootPrivileges) + if ok, err := checkPrivileges(); !ok { + return installAction + failed, err } srvPath := linux.servicePath() - if linux.checkInstalled() == true { - return installAction + failed, errors.New(linux.description + " already installed") + if linux.isInstalled() { + return installAction + failed, ErrAlreadyInstalled } file, err := os.Create(srvPath) @@ -112,12 +111,12 @@ func (linux *systemVRecord) Install() (string, error) { func (linux *systemVRecord) Remove() (string, error) { removeAction := "Removing " + linux.description + ":" - if checkPrivileges() == false { - return removeAction + failed, errors.New(rootPrivileges) + if ok, err := checkPrivileges(); !ok { + return removeAction + failed, err } - if linux.checkInstalled() == false { - return removeAction + failed, errors.New(linux.description + " is not installed") + if !linux.isInstalled() { + return removeAction + failed, ErrNotInstalled } if err := os.Remove(linux.servicePath()); err != nil { @@ -142,16 +141,16 @@ func (linux *systemVRecord) Remove() (string, error) { func (linux *systemVRecord) Start() (string, error) { startAction := "Starting " + linux.description + ":" - if checkPrivileges() == false { - return startAction + failed, errors.New(rootPrivileges) + if ok, err := checkPrivileges(); !ok { + return startAction + failed, err } - if linux.checkInstalled() == false { - return startAction + failed, errors.New(linux.description + " is not installed") + if !linux.isInstalled() { + return startAction + failed, ErrNotInstalled } - if _, status := linux.checkRunning(); status == true { - return startAction + failed, errors.New("service already running") + if _, ok := linux.checkRunning(); ok { + return startAction + failed, ErrAlreadyRunning } if err := exec.Command("service", linux.name, "start").Run(); err != nil { @@ -165,16 +164,16 @@ func (linux *systemVRecord) Start() (string, error) { func (linux *systemVRecord) Stop() (string, error) { stopAction := "Stopping " + linux.description + ":" - if checkPrivileges() == false { - return stopAction + failed, errors.New(rootPrivileges) + if ok, err := checkPrivileges(); !ok { + return stopAction + failed, err } - if linux.checkInstalled() == false { - return stopAction + failed, errors.New(linux.description + " is not installed") + if !linux.isInstalled() { + return stopAction + failed, ErrNotInstalled } - if _, status := linux.checkRunning(); status == false { - return stopAction + failed, errors.New("service already stopped") + if _, ok := linux.checkRunning(); !ok { + return stopAction + failed, ErrAlreadyStopped } if err := exec.Command("service", linux.name, "stop").Run(); err != nil { @@ -187,12 +186,12 @@ func (linux *systemVRecord) Stop() (string, error) { // Status - Get service status func (linux *systemVRecord) Status() (string, error) { - if checkPrivileges() == false { - return "", errors.New(rootPrivileges) + if ok, err := checkPrivileges(); !ok { + return "", err } - if linux.checkInstalled() == false { - return "Status could not defined", errors.New(linux.description + " is not installed") + if !linux.isInstalled() { + return "Status could not defined", ErrNotInstalled } statusAction, _ := linux.checkRunning() From 0474006ecae4ef1faf84954b5d4998de24fba8bd Mon Sep 17 00:00:00 2001 From: Igor Dolzhikov Date: Fri, 11 Mar 2016 13:45:32 +0700 Subject: [PATCH 3/6] used ErrWindowsUnsupported --- daemon_windows.go | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) diff --git a/daemon_windows.go b/daemon_windows.go index 3c4e644..00ec90c 100644 --- a/daemon_windows.go +++ b/daemon_windows.go @@ -9,6 +9,8 @@ import ( "errors" ) +var ErrWindowsUnsupported = errors.New("windows daemon is not supported") + // windowsRecord - standard record (struct) for windows version of daemon package type windowsRecord struct { name string @@ -25,37 +27,37 @@ func newDaemon(name, description string, dependencies []string) (Daemon, error) func (windows *windowsRecord) Install() (string, error) { installAction := "Install " + windows.description + ":" - return installAction + failed, errors.New("windows daemon is not supported") + return installAction + failed, ErrWindowsUnsupported } // Remove the service func (windows *windowsRecord) Remove() (string, error) { removeAction := "Removing " + windows.description + ":" - return removeAction + failed, errors.New("windows daemon is not supported") + return removeAction + failed, ErrWindowsUnsupported } // Start the service func (windows *windowsRecord) Start() (string, error) { startAction := "Starting " + windows.description + ":" - return startAction + failed, errors.New("windows daemon is not supported") + return startAction + failed, ErrWindowsUnsupported } // Stop the service func (windows *windowsRecord) Stop() (string, error) { stopAction := "Stopping " + windows.description + ":" - return stopAction + failed, errors.New("windows daemon is not supported") + return stopAction + failed, ErrWindowsUnsupported } // Status - Get service status func (windows *windowsRecord) Status() (string, error) { - return "Status could not defined", errors.New("windows daemon is not supported") + return "Status could not defined", ErrWindowsUnsupported } // Get executable path func execPath() (string, error) { - return "", errors.New("windows daemon is not supported") + return "", ErrWindowsUnsupported } From b4372c02f092e44ff4d918ac5aaaee25dbc482ef Mon Sep 17 00:00:00 2001 From: Igor Dolzhikov Date: Fri, 11 Mar 2016 13:46:29 +0700 Subject: [PATCH 4/6] remove dates from example logging --- example/myservice.go | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/example/myservice.go b/example/myservice.go index b3efdf2..12fcfe1 100644 --- a/example/myservice.go +++ b/example/myservice.go @@ -118,8 +118,8 @@ func handleClient(client net.Conn) { } func init() { - stdlog = log.New(os.Stdout, "", log.Ldate|log.Ltime) - errlog = log.New(os.Stderr, "", log.Ldate|log.Ltime) + stdlog = log.New(os.Stdout, "", 0) + errlog = log.New(os.Stderr, "", 0) } func main() { From ad79a20d8b74d6c8ccf18460951a1aeebe2c747e Mon Sep 17 00:00:00 2001 From: Igor Dolzhikov Date: Fri, 11 Mar 2016 14:00:41 +0700 Subject: [PATCH 5/6] Bumped version number to 0.3.1 --- daemon.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/daemon.go b/daemon.go index 04236e7..9d399c5 100644 --- a/daemon.go +++ b/daemon.go @@ -3,7 +3,7 @@ // license that can be found in the LICENSE file. /* -Package daemon 0.3.0 for use with Go (golang) services. +Package daemon 0.3.1 for use with Go (golang) services. Package daemon provides primitives for daemonization of golang services. This package is not provide implementation of user daemon, From ce61f4623eb37b8acbb290e4661e5802d11e280a Mon Sep 17 00:00:00 2001 From: Igor Dolzhikov Date: Fri, 11 Mar 2016 14:04:12 +0700 Subject: [PATCH 6/6] copyright --- LICENSE | 2 +- daemon.go | 2 +- daemon_darwin.go | 2 +- daemon_linux.go | 2 +- daemon_linux_systemd.go | 2 +- daemon_linux_systemv.go | 2 +- daemon_windows.go | 2 +- helper.go | 4 ++++ 8 files changed, 11 insertions(+), 7 deletions(-) diff --git a/LICENSE b/LICENSE index 58207aa..1399597 100644 --- a/LICENSE +++ b/LICENSE @@ -1,6 +1,6 @@ The MIT License (MIT) -Copyright (c) 2014 Igor Dolzhikov +Copyright (c) 2016 Igor Dolzhikov Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal diff --git a/daemon.go b/daemon.go index 9d399c5..ec31b36 100644 --- a/daemon.go +++ b/daemon.go @@ -1,4 +1,4 @@ -// Copyright 2015 Igor Dolzhikov. All rights reserved. +// Copyright 2016 Igor Dolzhikov. All rights reserved. // Use of this source code is governed by // license that can be found in the LICENSE file. diff --git a/daemon_darwin.go b/daemon_darwin.go index 320fe1a..c4109b5 100644 --- a/daemon_darwin.go +++ b/daemon_darwin.go @@ -1,4 +1,4 @@ -// Copyright 2015 Igor Dolzhikov. All rights reserved. +// Copyright 2016 Igor Dolzhikov. All rights reserved. // Use of this source code is governed by // license that can be found in the LICENSE file. diff --git a/daemon_linux.go b/daemon_linux.go index affc0b4..da0d873 100644 --- a/daemon_linux.go +++ b/daemon_linux.go @@ -1,4 +1,4 @@ -// Copyright 2015 Igor Dolzhikov. All rights reserved. +// Copyright 2016 Igor Dolzhikov. All rights reserved. // Use of this source code is governed by // license that can be found in the LICENSE file. diff --git a/daemon_linux_systemd.go b/daemon_linux_systemd.go index c4e915a..6c6c0a5 100644 --- a/daemon_linux_systemd.go +++ b/daemon_linux_systemd.go @@ -1,4 +1,4 @@ -// Copyright 2015 Igor Dolzhikov. All rights reserved. +// Copyright 2016 Igor Dolzhikov. All rights reserved. // Use of this source code is governed by // license that can be found in the LICENSE file. diff --git a/daemon_linux_systemv.go b/daemon_linux_systemv.go index 1cde022..a7c0fd5 100644 --- a/daemon_linux_systemv.go +++ b/daemon_linux_systemv.go @@ -1,4 +1,4 @@ -// Copyright 2015 Igor Dolzhikov. All rights reserved. +// Copyright 2016 Igor Dolzhikov. All rights reserved. // Use of this source code is governed by // license that can be found in the LICENSE file. diff --git a/daemon_windows.go b/daemon_windows.go index 00ec90c..805ee18 100644 --- a/daemon_windows.go +++ b/daemon_windows.go @@ -1,4 +1,4 @@ -// Copyright 2015 Igor Dolzhikov. All rights reserved. +// Copyright 2016 Igor Dolzhikov. All rights reserved. // Use of this source code is governed by // license that can be found in the LICENSE file. diff --git a/helper.go b/helper.go index 7a83f8b..b158836 100644 --- a/helper.go +++ b/helper.go @@ -1,3 +1,7 @@ +// Copyright 2016 Igor Dolzhikov. All rights reserved. +// Use of this source code is governed by +// license that can be found in the LICENSE file. + package daemon import (