Merge pull request #532 from NextTurn/args

Support <startarguments> and <stoparguments>
pull/513/head
Oleg Nenashev 2020-05-10 23:00:14 +02:00 committed by GitHub
commit 3ca706678c
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
6 changed files with 62 additions and 42 deletions

View File

@ -92,9 +92,9 @@ Optionally set a different logging directory with `<logpath>` and startup `<logm
See the [Logging and error reporting](loggingAndErrorReporting.md) page for more info. See the [Logging and error reporting](loggingAndErrorReporting.md) page for more info.
### argument ### Arguments
This element specifies the arguments to be passed to the executable. `<argument>` element specifies the arguments to be passed to the executable.
Winsw will quote each argument if necessary, so do not put quotes in `<argument>` to avoid double quotation. Winsw will quote each argument if necessary, so do not put quotes in `<argument>` to avoid double quotation.
```xml ```xml
@ -107,12 +107,12 @@ Winsw will quote each argument if necessary, so do not put quotes in `<argument>
### stopargument/stopexecutable ### stopargument/stopexecutable
When the service is requested to stop, winsw simply calls [TerminateProcess function](https://docs.microsoft.com/windows/win32/api/processthreadsapi/nf-processthreadsapi-terminateprocess) to kill the service instantly. ~~When the service is requested to stop, winsw simply calls [TerminateProcess function](https://docs.microsoft.com/windows/win32/api/processthreadsapi/nf-processthreadsapi-terminateprocess) to kill the service instantly.~~
However, if `<stopargument>` elements are present, winsw will instead launch another process of `<executable>` (or `<stopexecutable>` if that's specified) with the `<stopargument>` arguments, and expects that to initiate the graceful shutdown of the service process. However, if `<stopargument>`/`<stoparguments>` elements are present, winsw will instead launch another process of `<executable>` (or `<stopexecutable>` if that's specified) with the specified arguments, and expects that to initiate the graceful shutdown of the service process.
Winsw will then wait for the two processes to exit on its own, before reporting back to Windows that the service has terminated. Winsw will then wait for the two processes to exit on its own, before reporting back to Windows that the service has terminated.
When you use the `<stopargument>`, you must use `<startargument>` instead of `<argument>`. See the complete example below: When you use the `<stopargument>`/`<stoparguments>`, you must use `<startargument>`/`<startarguments>` instead of `<argument>`. See the complete example below:
```xml ```xml
<executable>catalina.sh</executable> <executable>catalina.sh</executable>
@ -123,9 +123,6 @@ When you use the `<stopargument>`, you must use `<startargument>` instead of `<a
<stopargument>stop</stopargument> <stopargument>stop</stopargument>
``` ```
Note that the name of the element is `startargument` and not `startarguments`.
As such, to specify multiple arguments, you'll specify multiple elements.
### stoptimeout ### stoptimeout
When the service is requested to stop, winsw first attempts to send a Ctrl+C signal, When the service is requested to stop, winsw first attempts to send a Ctrl+C signal,

View File

@ -157,7 +157,7 @@ SECTION: Executable management
This OPTION also enables termination of the executable via stop executable This OPTION also enables termination of the executable via stop executable
--> -->
<!-- <!--
<stoparguments>-stop true</stoparguments>--> <stoparguments>-stop true</stoparguments>
--> -->
<!-- <!--
SECTION: Service management SECTION: Service management

View File

@ -268,31 +268,31 @@ namespace winsw
} }
#endif #endif
string? startarguments = _descriptor.Startarguments; string? startArguments = _descriptor.StartArguments;
if (startarguments is null) if (startArguments is null)
{ {
startarguments = _descriptor.Arguments; startArguments = _descriptor.Arguments;
} }
else else
{ {
startarguments += " " + _descriptor.Arguments; startArguments += " " + _descriptor.Arguments;
} }
// Converting newlines, line returns, tabs into a single // Converting newlines, line returns, tabs into a single
// space. This allows users to provide multi-line arguments // space. This allows users to provide multi-line arguments
// in the xml for readability. // in the xml for readability.
startarguments = Regex.Replace(startarguments, @"\s*[\n\r]+\s*", " "); startArguments = Regex.Replace(startArguments, @"\s*[\n\r]+\s*", " ");
LogEvent("Starting " + _descriptor.Executable + ' ' + startarguments); LogEvent("Starting " + _descriptor.Executable + ' ' + startArguments);
Log.Info("Starting " + _descriptor.Executable + ' ' + startarguments); Log.Info("Starting " + _descriptor.Executable + ' ' + startArguments);
// Load and start extensions // Load and start extensions
ExtensionManager.LoadExtensions(); ExtensionManager.LoadExtensions();
ExtensionManager.FireOnWrapperStarted(); ExtensionManager.FireOnWrapperStarted();
LogHandler executableLogHandler = CreateExecutableLogHandler(); LogHandler executableLogHandler = CreateExecutableLogHandler();
StartProcess(_process, startarguments, _descriptor.Executable, executableLogHandler, true); StartProcess(_process, startArguments, _descriptor.Executable, executableLogHandler, true);
ExtensionManager.FireOnProcessStarted(_process); ExtensionManager.FireOnProcessStarted(_process);
_process.StandardInput.Close(); // nothing for you to read! _process.StandardInput.Close(); // nothing for you to read!
@ -332,12 +332,12 @@ namespace winsw
/// </summary> /// </summary>
private void StopIt() private void StopIt()
{ {
string? stoparguments = _descriptor.Stoparguments; string? stopArguments = _descriptor.StopArguments;
LogEvent("Stopping " + _descriptor.Id); LogEvent("Stopping " + _descriptor.Id);
Log.Info("Stopping " + _descriptor.Id); Log.Info("Stopping " + _descriptor.Id);
_orderlyShutdown = true; _orderlyShutdown = true;
if (stoparguments is null) if (stopArguments is null)
{ {
try try
{ {
@ -354,7 +354,7 @@ namespace winsw
{ {
SignalShutdownPending(); SignalShutdownPending();
stoparguments += " " + _descriptor.Arguments; stopArguments += " " + _descriptor.Arguments;
Process stopProcess = new Process(); Process stopProcess = new Process();
string? executable = _descriptor.StopExecutable; string? executable = _descriptor.StopExecutable;
@ -362,7 +362,7 @@ namespace winsw
executable ??= _descriptor.Executable; executable ??= _descriptor.Executable;
// TODO: Redirect logging to Log4Net once https://github.com/kohsuke/winsw/pull/213 is integrated // TODO: Redirect logging to Log4Net once https://github.com/kohsuke/winsw/pull/213 is integrated
StartProcess(stopProcess, stoparguments, executable, null, false); StartProcess(stopProcess, stopArguments, executable, null, false);
Log.Debug("WaitForProcessToExit " + _process.Id + "+" + stopProcess.Id); Log.Debug("WaitForProcessToExit " + _process.Id + "+" + stopProcess.Id);
WaitForProcessToExit(_process); WaitForProcessToExit(_process);

View File

@ -29,9 +29,9 @@ namespace winsw.Configuration
// Executable management // Executable management
public string Arguments => string.Empty; public string Arguments => string.Empty;
public string? Startarguments => null; public string? StartArguments => null;
public string? StopExecutable => null; public string? StopExecutable => null;
public string? Stoparguments => null; public string? StopArguments => null;
public string WorkingDirectory => Path.GetDirectoryName(ExecutablePath)!; public string WorkingDirectory => Path.GetDirectoryName(ExecutablePath)!;
public ProcessPriorityClass Priority => ProcessPriorityClass.Normal; public ProcessPriorityClass Priority => ProcessPriorityClass.Normal;
public TimeSpan StopTimeout => TimeSpan.FromSeconds(15); public TimeSpan StopTimeout => TimeSpan.FromSeconds(15);

View File

@ -26,9 +26,9 @@ namespace winsw.Configuration
// Executable management // Executable management
string Arguments { get; } string Arguments { get; }
string? Startarguments { get; } string? StartArguments { get; }
string? StopExecutable { get; } string? StopExecutable { get; }
string? Stoparguments { get; } string? StopArguments { get; }
string WorkingDirectory { get; } string WorkingDirectory { get; }
ProcessPriorityClass Priority { get; } ProcessPriorityClass Priority { get; }
TimeSpan StopTimeout { get; } TimeSpan StopTimeout { get; }

View File

@ -185,7 +185,7 @@ namespace winsw
public string? StopExecutable => SingleElement("stopexecutable", true); public string? StopExecutable => SingleElement("stopexecutable", true);
/// <summary> /// <summary>
/// Arguments or multiple optional argument elements which overrule the arguments element. /// <c>arguments</c> or multiple optional <c>argument</c> elements which overrule the arguments element.
/// </summary> /// </summary>
public string Arguments public string Arguments
{ {
@ -193,33 +193,56 @@ namespace winsw
{ {
string? arguments = AppendTags("argument", null); string? arguments = AppendTags("argument", null);
if (arguments is null) if (!(arguments is null))
{
XmlNode? argumentsNode = dom.SelectSingleNode("//arguments");
if (argumentsNode is null)
{
return Defaults.Arguments;
}
return Environment.ExpandEnvironmentVariables(argumentsNode.InnerText);
}
else
{ {
return arguments; return arguments;
} }
XmlNode? argumentsNode = dom.SelectSingleNode("//arguments");
return argumentsNode is null ? Defaults.Arguments : Environment.ExpandEnvironmentVariables(argumentsNode.InnerText);
} }
} }
/// <summary> /// <summary>
/// Multiple optional startargument elements. /// <c>startarguments</c> or multiple optional <c>startargument</c> elements.
/// </summary> /// </summary>
public string? Startarguments => AppendTags("startargument", Defaults.Startarguments); public string? StartArguments
{
get
{
string? startArguments = AppendTags("startargument", null);
if (!(startArguments is null))
{
return startArguments;
}
XmlNode? startArgumentsNode = dom.SelectSingleNode("//startarguments");
return startArgumentsNode is null ? null : Environment.ExpandEnvironmentVariables(startArgumentsNode.InnerText);
}
}
/// <summary> /// <summary>
/// Multiple optional stopargument elements. /// <c>stoparguments</c> or multiple optional <c>stopargument</c> elements.
/// </summary> /// </summary>
public string? Stoparguments => AppendTags("stopargument", Defaults.Stoparguments); public string? StopArguments
{
get
{
string? stopArguments = AppendTags("stopargument", null);
if (!(stopArguments is null))
{
return stopArguments;
}
XmlNode? stopArgumentsNode = dom.SelectSingleNode("//stoparguments");
return stopArgumentsNode is null ? null : Environment.ExpandEnvironmentVariables(stopArgumentsNode.InnerText);
}
}
public string WorkingDirectory public string WorkingDirectory
{ {