commit af636848622c8ad27cace63be5f9dd9aaa565502 Author: Andrey Nering Date: Mon Jan 23 20:40:11 2017 -0200 Squashed 'modules/minwinsvc/' content from commit cad6b2b git-subtree-dir: modules/minwinsvc git-subtree-split: cad6b2b879b0970e4245a20ebf1a81a756e2bb70 diff --git a/LICENSE b/LICENSE new file mode 100644 index 0000000000..fce91b4e1a --- /dev/null +++ b/LICENSE @@ -0,0 +1,20 @@ +Copyright (c) 2015 Daniel Theophanes + +This software is provided 'as-is', without any express or implied +warranty. In no event will the authors be held liable for any damages +arising from the use of this software. + +Permission is granted to anyone to use this software for any purpose, +including commercial applications, and to alter it and redistribute it +freely, subject to the following restrictions: + + 1. The origin of this software must not be misrepresented; you must not + claim that you wrote the original software. If you use this software + in a product, an acknowledgment in the product documentation would be + appreciated but is not required. + + 2. Altered source versions must be plainly marked as such, and must not be + misrepresented as being the original software. + + 3. This notice may not be removed or altered from any source + distribution. diff --git a/README.md b/README.md new file mode 100644 index 0000000000..260dceeac3 --- /dev/null +++ b/README.md @@ -0,0 +1,18 @@ +### Minimal windows service stub + +Programs designed to run from most *nix style operating systems +can import this package to enable running programs as services without modifying +them. + +``` +import _ "github.com/kardianos/minwinsvc" +``` + +If you need more control over the exit behavior, set +``` +minwinsvc.SetOnExit(func() { + // Do something. + // Within 10 seconds call: + os.Exit(0) +}) +``` diff --git a/minwinsvc.go b/minwinsvc.go new file mode 100644 index 0000000000..057ba7f954 --- /dev/null +++ b/minwinsvc.go @@ -0,0 +1,18 @@ +// Copyright 2015 Daniel Theophanes. +// Use of this source code is governed by a zlib-style +// license that can be found in the LICENSE file.package service + +// Minimal non-invasive windows only service stub. +// +// Import to allow running as a windows service. +// import _ "github.com/kardianos/minwinsvc" +// This will detect if running as a windows service +// and install required callbacks for windows. +package minwinsvc + +// SetOnExit sets the function to be called when the windows service +// requests an exit. If this is not called, or if it is called where +// f == nil, then it defaults to calling "os.Exit(0)". +func SetOnExit(f func()) { + setOnExit(f) +} diff --git a/svc_other.go b/svc_other.go new file mode 100644 index 0000000000..197d30021f --- /dev/null +++ b/svc_other.go @@ -0,0 +1,11 @@ +// Copyright 2015 Daniel Theophanes. +// Use of this source code is governed by a zlib-style +// license that can be found in the LICENSE file.package service + +//+build !windows + +package minwinsvc + +func setOnExit(f func()) { + // Nothing. +} diff --git a/svc_windows.go b/svc_windows.go new file mode 100644 index 0000000000..91e2b6a4dd --- /dev/null +++ b/svc_windows.go @@ -0,0 +1,70 @@ +// Copyright 2015 Daniel Theophanes. +// Use of this source code is governed by a zlib-style +// license that can be found in the LICENSE file.package service + +//+build windows + +package minwinsvc + +import ( + "os" + "sync" + + "golang.org/x/sys/windows/svc" +) + +var ( + onExit func() + guard sync.Mutex +) + +func init() { + interactive, err := svc.IsAnInteractiveSession() + if err != nil { + panic(err) + } + if interactive { + return + } + go func() { + _ = svc.Run("", runner{}) + + guard.Lock() + f := onExit + guard.Unlock() + + // Don't hold this lock in user code. + if f != nil { + f() + } + // Make sure we exit. + os.Exit(0) + }() +} + +func setOnExit(f func()) { + guard.Lock() + onExit = f + guard.Unlock() +} + +type runner struct{} + +func (runner) Execute(args []string, r <-chan svc.ChangeRequest, changes chan<- svc.Status) (bool, uint32) { + const cmdsAccepted = svc.AcceptStop | svc.AcceptShutdown + changes <- svc.Status{State: svc.StartPending} + + changes <- svc.Status{State: svc.Running, Accepts: cmdsAccepted} + for { + c := <-r + switch c.Cmd { + case svc.Interrogate: + changes <- c.CurrentStatus + case svc.Stop, svc.Shutdown: + changes <- svc.Status{State: svc.StopPending} + return false, 0 + } + } + + return false, 0 +}