@@ -9,13 +9,12 @@ import (
9
9
"errors"
10
10
"fmt"
11
11
"os/exec"
12
+ "regexp"
12
13
"syscall"
13
14
"unicode/utf16"
14
15
"unsafe"
15
16
)
16
17
17
- var ErrWindowsUnsupported = errors .New ("Adding as a service failed. Download and place nssm.exe in the path to install this service as an service. NSSM url: https://nssm.cc/" )
18
-
19
18
// windowsRecord - standard record (struct) for windows version of daemon package
20
19
type windowsRecord struct {
21
20
name string
@@ -31,59 +30,50 @@ func newDaemon(name, description string, dependencies []string) (Daemon, error)
31
30
// Install the service
32
31
func (windows * windowsRecord ) Install (args ... string ) (string , error ) {
33
32
installAction := "Install " + windows .description + ":"
34
- adminAccessNecessary := "Administrator access is needed to install a service."
35
33
36
34
execp , err := execPath ()
37
35
38
36
if err != nil {
39
37
return installAction + failed , err
40
38
}
41
39
42
- cmdArgs := []string {"install " , windows .name , execp }
40
+ cmdArgs := []string {"create " , windows .name , "start=auto" , "binPath=" + execp }
43
41
cmdArgs = append (cmdArgs , args ... )
44
42
45
- cmd := exec .Command ("nssm.exe " , cmdArgs ... )
46
- out , err : = cmd .Output ()
43
+ cmd := exec .Command ("sc " , cmdArgs ... )
44
+ _ , err = cmd .Output ()
47
45
if err != nil {
48
- if len (out ) > 0 {
49
- fmt .Println (string (out ))
50
- } else {
51
- fmt .Println ("No output. Probably service already exists. Try uninstall first." )
52
- }
53
- return installAction + failed , err
54
- }
55
- if len (out ) == 0 {
56
- return adminAccessNecessary , errors .New (adminAccessNecessary )
46
+ return installAction + failed , getWindowsError (err )
57
47
}
58
48
return installAction + " completed." , nil
59
49
}
60
50
61
51
// Remove the service
62
52
func (windows * windowsRecord ) Remove () (string , error ) {
63
53
removeAction := "Removing " + windows .description + ":"
64
- cmd := exec .Command ("nssm.exe " , "remove " , windows .name , "confirm" )
54
+ cmd := exec .Command ("sc " , "delete " , windows .name , "confirm" )
65
55
err := cmd .Run ()
66
56
if err != nil {
67
- return removeAction + failed , err
57
+ return removeAction + failed , getWindowsError ( err )
68
58
}
69
59
return removeAction + " completed." , nil
70
60
}
71
61
72
62
// Start the service
73
63
func (windows * windowsRecord ) Start () (string , error ) {
74
64
startAction := "Starting " + windows .description + ":"
75
- cmd := exec .Command ("nssm.exe " , "start" , windows .name )
65
+ cmd := exec .Command ("sc " , "start" , windows .name )
76
66
err := cmd .Run ()
77
67
if err != nil {
78
- return startAction + failed , err
68
+ return startAction + failed , getWindowsError ( err )
79
69
}
80
70
return startAction + " completed." , nil
81
71
}
82
72
83
73
// Stop the service
84
74
func (windows * windowsRecord ) Stop () (string , error ) {
85
75
stopAction := "Stopping " + windows .description + ":"
86
- cmd := exec .Command ("nssm.exe " , "stop" , windows .name )
76
+ cmd := exec .Command ("sc " , "stop" , windows .name )
87
77
err := cmd .Run ()
88
78
if err != nil {
89
79
return stopAction + failed , err
@@ -93,12 +83,12 @@ func (windows *windowsRecord) Stop() (string, error) {
93
83
94
84
// Status - Get service status
95
85
func (windows * windowsRecord ) Status () (string , error ) {
96
- cmd := exec .Command ("nssm.exe " , "status " , windows .name )
86
+ cmd := exec .Command ("sc " , "query " , windows .name )
97
87
out , err := cmd .Output ()
98
88
if err != nil {
99
- return "Getting status:" + failed , err
89
+ return "Getting status:" + failed , getWindowsError ( err )
100
90
}
101
- return "Status: " + string (out ), nil
91
+ return "Status: " + "SERVICE_" + getWindowsServiceState (out ), nil
102
92
}
103
93
104
94
// Get executable path
@@ -118,3 +108,24 @@ func execPath() (string, error) {
118
108
}
119
109
return string (utf16 .Decode (b [0 :n ])), nil
120
110
}
111
+
112
+ // Get windows error
113
+ func getWindowsError (inputError error ) error {
114
+ if exiterr , ok := inputError .(* exec.ExitError ); ok {
115
+ if status , ok := exiterr .Sys ().(syscall.WaitStatus ); ok {
116
+ if sysErr , ok := WinErrCode [status .ExitStatus ()]; ok {
117
+ return errors .New (fmt .Sprintf ("\n %s: %s \n %s" , sysErr .Title , sysErr .Description , sysErr .Action ))
118
+ }
119
+ }
120
+ }
121
+
122
+ return inputError
123
+ }
124
+
125
+ // Get windows service state
126
+ func getWindowsServiceState (out []byte ) string {
127
+ regex := regexp .MustCompile ("STATE.*: (?P<state_code>[0-9]) (?P<state>.*) " )
128
+ service := regex .FindAllStringSubmatch (string (out ), - 1 )[0 ]
129
+
130
+ return service [2 ]
131
+ }
0 commit comments