summaryrefslogtreecommitdiffstats
path: root/modules/minwinsvc/svc_windows.go
blob: 609bf06d3a8b1b34cbe354223ac796f536050434 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
// 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"
	"strconv"
	"sync"

	"golang.org/x/sys/windows/svc"
)

var (
	onExit  func()
	guard   sync.Mutex
	skip, _ = strconv.ParseBool(os.Getenv("SKIP_MINWINSVC"))
	isSSH   = os.Getenv("SSH_ORIGINAL_COMMAND") != ""
)

func init() {
	if skip || isSSH {
		return
	}
	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
}