Skip to content

Commit 29a7daa

Browse files
committed
Merge branch 'release/0.10.3'
2 parents 57605ba + 904cd17 commit 29a7daa

File tree

4 files changed

+164
-24
lines changed

4 files changed

+164
-24
lines changed

README.md

+1
Original file line numberDiff line numberDiff line change
@@ -198,6 +198,7 @@ See `examples/cron/cron_job.go`
198198
- [0X8C - Demired](https://github.com/Demired)
199199
- [Maximus](https://github.com/maximus12793)
200200
- [AlgorathDev](https://github.com/AlgorathDev)
201+
- [Alexis Camilleri](https://github.com/krysennn)
201202

202203
All the contributors are welcome. If you would like to be the contributor please accept some rules.
203204

daemon.go

+1-1
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33
// license that can be found in the LICENSE file.
44

55
/*
6-
Package daemon 0.10.2 for use with Go (golang) services.
6+
Package daemon 0.10.3 for use with Go (golang) services.
77
88
Package daemon provides primitives for daemonization of golang services.
99
This package is not provide implementation of user daemon,

daemon_windows.go

+34-23
Original file line numberDiff line numberDiff line change
@@ -9,13 +9,12 @@ import (
99
"errors"
1010
"fmt"
1111
"os/exec"
12+
"regexp"
1213
"syscall"
1314
"unicode/utf16"
1415
"unsafe"
1516
)
1617

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-
1918
// windowsRecord - standard record (struct) for windows version of daemon package
2019
type windowsRecord struct {
2120
name string
@@ -31,59 +30,50 @@ func newDaemon(name, description string, dependencies []string) (Daemon, error)
3130
// Install the service
3231
func (windows *windowsRecord) Install(args ...string) (string, error) {
3332
installAction := "Install " + windows.description + ":"
34-
adminAccessNecessary := "Administrator access is needed to install a service."
3533

3634
execp, err := execPath()
3735

3836
if err != nil {
3937
return installAction + failed, err
4038
}
4139

42-
cmdArgs := []string{"install", windows.name, execp}
40+
cmdArgs := []string{"create", windows.name, "start=auto", "binPath=" + execp}
4341
cmdArgs = append(cmdArgs, args...)
4442

45-
cmd := exec.Command("nssm.exe", cmdArgs...)
46-
out, err := cmd.Output()
43+
cmd := exec.Command("sc", cmdArgs...)
44+
_, err = cmd.Output()
4745
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)
5747
}
5848
return installAction + " completed.", nil
5949
}
6050

6151
// Remove the service
6252
func (windows *windowsRecord) Remove() (string, error) {
6353
removeAction := "Removing " + windows.description + ":"
64-
cmd := exec.Command("nssm.exe", "remove", windows.name, "confirm")
54+
cmd := exec.Command("sc", "delete", windows.name, "confirm")
6555
err := cmd.Run()
6656
if err != nil {
67-
return removeAction + failed, err
57+
return removeAction + failed, getWindowsError(err)
6858
}
6959
return removeAction + " completed.", nil
7060
}
7161

7262
// Start the service
7363
func (windows *windowsRecord) Start() (string, error) {
7464
startAction := "Starting " + windows.description + ":"
75-
cmd := exec.Command("nssm.exe", "start", windows.name)
65+
cmd := exec.Command("sc", "start", windows.name)
7666
err := cmd.Run()
7767
if err != nil {
78-
return startAction + failed, err
68+
return startAction + failed, getWindowsError(err)
7969
}
8070
return startAction + " completed.", nil
8171
}
8272

8373
// Stop the service
8474
func (windows *windowsRecord) Stop() (string, error) {
8575
stopAction := "Stopping " + windows.description + ":"
86-
cmd := exec.Command("nssm.exe", "stop", windows.name)
76+
cmd := exec.Command("sc", "stop", windows.name)
8777
err := cmd.Run()
8878
if err != nil {
8979
return stopAction + failed, err
@@ -93,12 +83,12 @@ func (windows *windowsRecord) Stop() (string, error) {
9383

9484
// Status - Get service status
9585
func (windows *windowsRecord) Status() (string, error) {
96-
cmd := exec.Command("nssm.exe", "status", windows.name)
86+
cmd := exec.Command("sc", "query", windows.name)
9787
out, err := cmd.Output()
9888
if err != nil {
99-
return "Getting status:" + failed, err
89+
return "Getting status:" + failed, getWindowsError(err)
10090
}
101-
return "Status: " + string(out), nil
91+
return "Status: " + "SERVICE_" + getWindowsServiceState(out), nil
10292
}
10393

10494
// Get executable path
@@ -118,3 +108,24 @@ func execPath() (string, error) {
118108
}
119109
return string(utf16.Decode(b[0:n])), nil
120110
}
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+
}

helper_windows.go

+128
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,128 @@
1+
// Copyright 2016 The Go Authors. All rights reserved.
2+
// Use of this source code is governed by
3+
// license that can be found in the LICENSE file.
4+
5+
package daemon
6+
7+
// SystemError contains error description and corresponded action helper to fix it
8+
type SystemError struct {
9+
Title string
10+
Description string
11+
Action string
12+
}
13+
14+
var (
15+
// WinErrCode - List of system errors from Microsoft source:
16+
// https://msdn.microsoft.com/en-us/library/windows/desktop/ms681385(v=vs.85).aspx
17+
WinErrCode = map[int]SystemError{
18+
5: SystemError{
19+
Title: "ERROR_ACCESS_DENIED",
20+
Description: "Access denied.",
21+
Action: "Administrator access is needed to install a service.",
22+
},
23+
1051: SystemError{
24+
Title: "ERROR_DEPENDENT_SERVICES_RUNNING",
25+
Description: "A stop control has been sent to a service that other running services are dependent on.",
26+
},
27+
1052: SystemError{
28+
Title: "ERROR_INVALID_SERVICE_CONTROL",
29+
Description: "The requested control is not valid for this service.",
30+
},
31+
1053: SystemError{
32+
Title: "ERROR_SERVICE_REQUEST_TIMEOUT",
33+
Description: "The service did not respond to the start or control request in a timely fashion.",
34+
},
35+
1054: SystemError{
36+
Title: "ERROR_SERVICE_NO_THREAD",
37+
Description: "A thread could not be created for the service.",
38+
},
39+
1055: SystemError{
40+
Title: "ERROR_SERVICE_DATABASE_LOCKED",
41+
Description: "The service database is locked.",
42+
},
43+
1056: SystemError{
44+
Title: "ERROR_SERVICE_ALREADY_RUNNING",
45+
Description: "An instance of the service is already running.",
46+
},
47+
1057: SystemError{
48+
Title: "ERROR_INVALID_SERVICE_ACCOUNT",
49+
Description: "The account name is invalid or does not exist, or the password is invalid for the account name specified.",
50+
},
51+
1058: SystemError{
52+
Title: "ERROR_SERVICE_DISABLED",
53+
Description: "The service cannot be started, either because it is disabled or because it has no enabled devices associated with it.",
54+
},
55+
1060: SystemError{
56+
Title: "ERROR_SERVICE_DOES_NOT_EXIST",
57+
Description: "The specified service does not exist as an installed service.",
58+
},
59+
1061: SystemError{
60+
Title: "ERROR_SERVICE_CANNOT_ACCEPT_CTRL",
61+
Description: "The service cannot accept control messages at this time.",
62+
},
63+
1062: SystemError{
64+
Title: "ERROR_SERVICE_NOT_ACTIVE",
65+
Description: "The service has not been started.",
66+
},
67+
1063: SystemError{
68+
Title: "ERROR_FAILED_SERVICE_CONTROLLER_CONNECT",
69+
Description: "The service process could not connect to the service controller.",
70+
},
71+
1064: SystemError{
72+
Title: "ERROR_EXCEPTION_IN_SERVICE",
73+
Description: "An exception occurred in the service when handling the control request.",
74+
},
75+
1066: SystemError{
76+
Title: "ERROR_SERVICE_SPECIFIC_ERROR",
77+
Description: "The service has returned a service-specific error code.",
78+
},
79+
1068: SystemError{
80+
Title: "ERROR_SERVICE_DEPENDENCY_FAIL",
81+
Description: "The dependency service or group failed to start.",
82+
},
83+
1069: SystemError{
84+
Title: "ERROR_SERVICE_LOGON_FAILED",
85+
Description: "The service did not start due to a logon failure.",
86+
},
87+
1070: SystemError{
88+
Title: "ERROR_SERVICE_START_HANG",
89+
Description: "After starting, the service hung in a start-pending state.",
90+
},
91+
1071: SystemError{
92+
Title: "ERROR_INVALID_SERVICE_LOCK",
93+
Description: "The specified service database lock is invalid.",
94+
},
95+
1072: SystemError{
96+
Title: "ERROR_SERVICE_MARKED_FOR_DELETE",
97+
Description: "The specified service has been marked for deletion.",
98+
},
99+
1073: SystemError{
100+
Title: "ERROR_SERVICE_EXISTS",
101+
Description: "The specified service already exists.",
102+
},
103+
1075: SystemError{
104+
Title: "ERROR_SERVICE_DEPENDENCY_DELETED",
105+
Description: "The dependency service does not exist or has been marked for deletion.",
106+
},
107+
1077: SystemError{
108+
Title: "ERROR_SERVICE_NEVER_STARTED",
109+
Description: "No attempts to start the service have been made since the last boot.",
110+
},
111+
1078: SystemError{
112+
Title: "ERROR_DUPLICATE_SERVICE_NAME",
113+
Description: "The name is already in use as either a service name or a service display name.",
114+
},
115+
1079: SystemError{
116+
Title: "ERROR_DIFFERENT_SERVICE_ACCOUNT",
117+
Description: "The account specified for this service is different from the account specified for other services running in the same process.",
118+
},
119+
1083: SystemError{
120+
Title: "ERROR_SERVICE_NOT_IN_EXE",
121+
Description: "The executable program that this service is configured to run in does not implement the service.",
122+
},
123+
1084: SystemError{
124+
Title: "ERROR_NOT_SAFEBOOT_SERVICE",
125+
Description: "This service cannot be started in Safe Mode.",
126+
},
127+
}
128+
)

0 commit comments

Comments
 (0)