mirror of https://github.com/winsw/winsw
Clean up styles
parent
6e9d25a7b5
commit
9808ae88e8
|
@ -1,8 +1,4 @@
|
||||||
using System;
|
using System.Diagnostics;
|
||||||
using System.Collections.Generic;
|
|
||||||
using System.Diagnostics;
|
|
||||||
using System.Text;
|
|
||||||
using winsw.Logging;
|
|
||||||
|
|
||||||
namespace winsw.Logging
|
namespace winsw.Logging
|
||||||
{
|
{
|
||||||
|
@ -11,7 +7,7 @@ namespace winsw.Logging
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public class WrapperServiceEventLogProvider : IServiceEventLogProvider
|
public class WrapperServiceEventLogProvider : IServiceEventLogProvider
|
||||||
{
|
{
|
||||||
public WrapperService service {get; set;}
|
public WrapperService service { get; set; }
|
||||||
|
|
||||||
public EventLog locate()
|
public EventLog locate()
|
||||||
{
|
{
|
||||||
|
|
|
@ -2,7 +2,7 @@
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Diagnostics;
|
using System.Diagnostics;
|
||||||
using System.IO;
|
using System.IO;
|
||||||
using System.Management;
|
using System.Reflection;
|
||||||
using System.Runtime.InteropServices;
|
using System.Runtime.InteropServices;
|
||||||
using System.ServiceProcess;
|
using System.ServiceProcess;
|
||||||
using System.Text;
|
using System.Text;
|
||||||
|
@ -12,15 +12,13 @@ using log4net.Appender;
|
||||||
using log4net.Config;
|
using log4net.Config;
|
||||||
using log4net.Core;
|
using log4net.Core;
|
||||||
using log4net.Layout;
|
using log4net.Layout;
|
||||||
using log4net.Repository.Hierarchy;
|
|
||||||
using Microsoft.Win32;
|
using Microsoft.Win32;
|
||||||
using winsw.Extensions;
|
using winsw.Extensions;
|
||||||
|
using winsw.Logging;
|
||||||
|
using winsw.Native;
|
||||||
using winsw.Util;
|
using winsw.Util;
|
||||||
using WMI;
|
using WMI;
|
||||||
using ServiceType = WMI.ServiceType;
|
using ServiceType = WMI.ServiceType;
|
||||||
using winsw.Native;
|
|
||||||
using System.Reflection;
|
|
||||||
using winsw.Logging;
|
|
||||||
|
|
||||||
namespace winsw
|
namespace winsw
|
||||||
{
|
{
|
||||||
|
@ -32,7 +30,7 @@ namespace winsw
|
||||||
private readonly ServiceDescriptor _descriptor;
|
private readonly ServiceDescriptor _descriptor;
|
||||||
private Dictionary<string, string> _envs;
|
private Dictionary<string, string> _envs;
|
||||||
|
|
||||||
internal WinSWExtensionManager ExtensionManager { private set; get; }
|
internal WinSWExtensionManager ExtensionManager { get; private set; }
|
||||||
|
|
||||||
private static readonly ILog Log = LogManager.GetLogger("WinSW");
|
private static readonly ILog Log = LogManager.GetLogger("WinSW");
|
||||||
private static readonly WrapperServiceEventLogProvider eventLogProvider = new WrapperServiceEventLogProvider();
|
private static readonly WrapperServiceEventLogProvider eventLogProvider = new WrapperServiceEventLogProvider();
|
||||||
|
@ -50,17 +48,12 @@ namespace winsw
|
||||||
/// <remarks>
|
/// <remarks>
|
||||||
/// The version will be taken from <see cref="AssemblyInfo"/>
|
/// The version will be taken from <see cref="AssemblyInfo"/>
|
||||||
/// </remarks>
|
/// </remarks>
|
||||||
public static Version Version
|
public static Version Version => Assembly.GetExecutingAssembly().GetName().Version;
|
||||||
{
|
|
||||||
get { return Assembly.GetExecutingAssembly().GetName().Version; }
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Indicates that the system is shutting down.
|
/// Indicates that the system is shutting down.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public bool IsShuttingDown {
|
public bool IsShuttingDown => _systemShuttingdown;
|
||||||
get { return _systemShuttingdown; }
|
|
||||||
}
|
|
||||||
|
|
||||||
public WrapperService(ServiceDescriptor descriptor)
|
public WrapperService(ServiceDescriptor descriptor)
|
||||||
{
|
{
|
||||||
|
@ -77,7 +70,7 @@ namespace winsw
|
||||||
eventLogProvider.service = this;
|
eventLogProvider.service = this;
|
||||||
}
|
}
|
||||||
|
|
||||||
public WrapperService() : this (new ServiceDescriptor())
|
public WrapperService() : this(new ServiceDescriptor())
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -93,7 +86,7 @@ namespace winsw
|
||||||
|
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
using (var tr = new StreamReader(file,Encoding.UTF8))
|
using (var tr = new StreamReader(file, Encoding.UTF8))
|
||||||
{
|
{
|
||||||
string line;
|
string line;
|
||||||
while ((line = tr.ReadLine()) != null)
|
while ((line = tr.ReadLine()) != null)
|
||||||
|
@ -114,7 +107,6 @@ namespace winsw
|
||||||
{
|
{
|
||||||
File.Delete(file);
|
File.Delete(file);
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
|
@ -199,7 +191,6 @@ namespace winsw
|
||||||
{
|
{
|
||||||
LogEvent("envar " + key + '=' + _envs[key]);
|
LogEvent("envar " + key + '=' + _envs[key]);
|
||||||
}*/
|
}*/
|
||||||
|
|
||||||
HandleFileCopies();
|
HandleFileCopies();
|
||||||
|
|
||||||
// handle downloads
|
// handle downloads
|
||||||
|
@ -217,6 +208,7 @@ namespace winsw
|
||||||
string errorMessage = "Failed to download " + d.From + " to " + d.To;
|
string errorMessage = "Failed to download " + d.From + " to " + d.To;
|
||||||
LogEvent(errorMessage + ". " + e.Message);
|
LogEvent(errorMessage + ". " + e.Message);
|
||||||
Log.Error(errorMessage, e);
|
Log.Error(errorMessage, e);
|
||||||
|
|
||||||
// TODO: move this code into the download logic
|
// TODO: move this code into the download logic
|
||||||
if (d.FailOnError)
|
if (d.FailOnError)
|
||||||
{
|
{
|
||||||
|
@ -254,7 +246,7 @@ namespace winsw
|
||||||
|
|
||||||
protected override void OnShutdown()
|
protected override void OnShutdown()
|
||||||
{
|
{
|
||||||
// WriteEvent("OnShutdown");
|
// WriteEvent("OnShutdown");
|
||||||
|
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
|
@ -269,7 +261,7 @@ namespace winsw
|
||||||
|
|
||||||
protected override void OnStop()
|
protected override void OnStop()
|
||||||
{
|
{
|
||||||
// WriteEvent("OnStop");
|
// WriteEvent("OnStop");
|
||||||
|
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
|
@ -356,12 +348,12 @@ namespace winsw
|
||||||
|
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
// WriteEvent("WaitForProcessToExit [start]");
|
// WriteEvent("WaitForProcessToExit [start]");
|
||||||
|
|
||||||
while (!processoWait.WaitForExit(effectiveProcessWaitSleepTime))
|
while (!processoWait.WaitForExit(effectiveProcessWaitSleepTime))
|
||||||
{
|
{
|
||||||
SignalShutdownPending();
|
SignalShutdownPending();
|
||||||
// WriteEvent("WaitForProcessToExit [repeat]");
|
// WriteEvent("WaitForProcessToExit [repeat]");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
catch (InvalidOperationException)
|
catch (InvalidOperationException)
|
||||||
|
@ -369,7 +361,7 @@ namespace winsw
|
||||||
// already terminated
|
// already terminated
|
||||||
}
|
}
|
||||||
|
|
||||||
// WriteEvent("WaitForProcessToExit [finished]");
|
// WriteEvent("WaitForProcessToExit [finished]");
|
||||||
}
|
}
|
||||||
|
|
||||||
private void SignalShutdownPending()
|
private void SignalShutdownPending()
|
||||||
|
@ -386,11 +378,10 @@ namespace winsw
|
||||||
effectiveWaitHint = (int)_descriptor.WaitHint.TotalMilliseconds;
|
effectiveWaitHint = (int)_descriptor.WaitHint.TotalMilliseconds;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
IntPtr handle = ServiceHandle;
|
IntPtr handle = ServiceHandle;
|
||||||
_wrapperServiceStatus.checkPoint++;
|
_wrapperServiceStatus.checkPoint++;
|
||||||
_wrapperServiceStatus.waitHint = effectiveWaitHint;
|
_wrapperServiceStatus.waitHint = effectiveWaitHint;
|
||||||
// WriteEvent("SignalShutdownPending " + wrapperServiceStatus.checkPoint + ":" + wrapperServiceStatus.waitHint);
|
// WriteEvent("SignalShutdownPending " + wrapperServiceStatus.checkPoint + ":" + wrapperServiceStatus.waitHint);
|
||||||
_wrapperServiceStatus.currentState = (int)State.SERVICE_STOP_PENDING;
|
_wrapperServiceStatus.currentState = (int)State.SERVICE_STOP_PENDING;
|
||||||
Advapi32.SetServiceStatus(handle, ref _wrapperServiceStatus);
|
Advapi32.SetServiceStatus(handle, ref _wrapperServiceStatus);
|
||||||
}
|
}
|
||||||
|
@ -399,16 +390,15 @@ namespace winsw
|
||||||
{
|
{
|
||||||
IntPtr handle = ServiceHandle;
|
IntPtr handle = ServiceHandle;
|
||||||
_wrapperServiceStatus.checkPoint++;
|
_wrapperServiceStatus.checkPoint++;
|
||||||
// WriteEvent("SignalShutdownComplete " + wrapperServiceStatus.checkPoint + ":" + wrapperServiceStatus.waitHint);
|
// WriteEvent("SignalShutdownComplete " + wrapperServiceStatus.checkPoint + ":" + wrapperServiceStatus.waitHint);
|
||||||
_wrapperServiceStatus.currentState = (int)State.SERVICE_STOPPED;
|
_wrapperServiceStatus.currentState = (int)State.SERVICE_STOPPED;
|
||||||
Advapi32.SetServiceStatus(handle, ref _wrapperServiceStatus);
|
Advapi32.SetServiceStatus(handle, ref _wrapperServiceStatus);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void StartProcess(Process processToStart, string arguments, String executable, LogHandler logHandler, bool redirectStdin)
|
private void StartProcess(Process processToStart, string arguments, String executable, LogHandler logHandler, bool redirectStdin)
|
||||||
{
|
{
|
||||||
|
|
||||||
// Define handler of the completed process
|
// Define handler of the completed process
|
||||||
ProcessCompletionCallback processCompletionCallback = delegate(Process proc)
|
ProcessCompletionCallback processCompletionCallback = proc =>
|
||||||
{
|
{
|
||||||
string msg = processToStart.Id + " - " + processToStart.StartInfo.FileName + " " + processToStart.StartInfo.Arguments;
|
string msg = processToStart.Id + " - " + processToStart.StartInfo.FileName + " " + processToStart.StartInfo.Arguments;
|
||||||
try
|
try
|
||||||
|
@ -425,6 +415,7 @@ namespace winsw
|
||||||
// restart the service automatically
|
// restart the service automatically
|
||||||
if (proc.ExitCode == 0)
|
if (proc.ExitCode == 0)
|
||||||
SignalShutdownComplete();
|
SignalShutdownComplete();
|
||||||
|
|
||||||
Environment.Exit(proc.ExitCode);
|
Environment.Exit(proc.ExitCode);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -485,7 +476,6 @@ namespace winsw
|
||||||
throw new WmiException(ReturnValue.NoSuchService);
|
throw new WmiException(ReturnValue.NoSuchService);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
// ReSharper disable once InconsistentNaming
|
// ReSharper disable once InconsistentNaming
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Runs the wrapper.
|
/// Runs the wrapper.
|
||||||
|
@ -498,7 +488,6 @@ namespace winsw
|
||||||
{
|
{
|
||||||
bool isCLIMode = _args.Length > 0;
|
bool isCLIMode = _args.Length > 0;
|
||||||
|
|
||||||
|
|
||||||
// If descriptor is not specified, initialize the new one (and load configs from there)
|
// If descriptor is not specified, initialize the new one (and load configs from there)
|
||||||
var d = descriptor ?? new ServiceDescriptor();
|
var d = descriptor ?? new ServiceDescriptor();
|
||||||
|
|
||||||
|
@ -506,7 +495,6 @@ namespace winsw
|
||||||
// STDIN and STDOUT of the child process will be handled independently.
|
// STDIN and STDOUT of the child process will be handled independently.
|
||||||
InitLoggers(d, isCLIMode);
|
InitLoggers(d, isCLIMode);
|
||||||
|
|
||||||
|
|
||||||
if (isCLIMode) // CLI mode, in-service mode otherwise
|
if (isCLIMode) // CLI mode, in-service mode otherwise
|
||||||
{
|
{
|
||||||
Log.Debug("Starting ServiceWrapper in the CLI mode");
|
Log.Debug("Starting ServiceWrapper in the CLI mode");
|
||||||
|
@ -527,7 +515,7 @@ namespace winsw
|
||||||
// and among other things it makes it difficult for the caller
|
// and among other things it makes it difficult for the caller
|
||||||
// to read stdout/stderr. Thus redirection becomes handy.
|
// to read stdout/stderr. Thus redirection becomes handy.
|
||||||
var f = new FileStream(args[1], FileMode.Create);
|
var f = new FileStream(args[1], FileMode.Create);
|
||||||
var w = new StreamWriter(f) {AutoFlush = true};
|
var w = new StreamWriter(f) { AutoFlush = true };
|
||||||
Console.SetOut(w);
|
Console.SetOut(w);
|
||||||
Console.SetError(w);
|
Console.SetError(w);
|
||||||
|
|
||||||
|
@ -551,7 +539,7 @@ namespace winsw
|
||||||
throw new Exception("Installation failure: Service with id '" + d.Id + "' already exists");
|
throw new Exception("Installation failure: Service with id '" + d.Id + "' already exists");
|
||||||
}
|
}
|
||||||
|
|
||||||
string username=null, password=null;
|
string username = null, password = null;
|
||||||
bool setallowlogonasaserviceright = false;
|
bool setallowlogonasaserviceright = false;
|
||||||
if (args.Count > 1 && args[1] == "/p")
|
if (args.Count > 1 && args[1] == "/p")
|
||||||
{
|
{
|
||||||
|
@ -584,7 +572,7 @@ namespace winsw
|
||||||
LogonAsAService.AddLogonAsAServiceRight(username);
|
LogonAsAService.AddLogonAsAServiceRight(username);
|
||||||
}
|
}
|
||||||
|
|
||||||
svc.Create (
|
svc.Create(
|
||||||
d.Id,
|
d.Id,
|
||||||
d.Caption,
|
d.Caption,
|
||||||
"\"" + d.ExecutablePath + "\"",
|
"\"" + d.ExecutablePath + "\"",
|
||||||
|
@ -629,8 +617,10 @@ namespace winsw
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (args[0] == "uninstall")
|
if (args[0] == "uninstall")
|
||||||
{
|
{
|
||||||
Log.Info("Uninstalling the service with id '" + d.Id + "'");
|
Log.Info("Uninstalling the service with id '" + d.Id + "'");
|
||||||
|
@ -639,6 +629,7 @@ namespace winsw
|
||||||
Log.Warn("The service with id '" + d.Id + "' does not exist. Nothing to uninstall");
|
Log.Warn("The service with id '" + d.Id + "' does not exist. Nothing to uninstall");
|
||||||
return; // there's no such service, so consider it already uninstalled
|
return; // there's no such service, so consider it already uninstalled
|
||||||
}
|
}
|
||||||
|
|
||||||
if (s.Started)
|
if (s.Started)
|
||||||
{
|
{
|
||||||
// We could fail the opeartion here, but it would be an incompatible change.
|
// We could fail the opeartion here, but it would be an incompatible change.
|
||||||
|
@ -664,31 +655,40 @@ namespace winsw
|
||||||
{
|
{
|
||||||
Log.Fatal("Failed to uninstall the service with id '" + d.Id + "'. WMI Error code is '" + e.ErrorCode + "'");
|
Log.Fatal("Failed to uninstall the service with id '" + d.Id + "'. WMI Error code is '" + e.ErrorCode + "'");
|
||||||
}
|
}
|
||||||
|
|
||||||
throw e;
|
throw e;
|
||||||
}
|
}
|
||||||
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (args[0] == "start")
|
if (args[0] == "start")
|
||||||
{
|
{
|
||||||
Log.Info("Starting the service with id '" + d.Id + "'");
|
Log.Info("Starting the service with id '" + d.Id + "'");
|
||||||
if (s == null) ThrowNoSuchService();
|
if (s == null)
|
||||||
|
ThrowNoSuchService();
|
||||||
|
|
||||||
s.StartService();
|
s.StartService();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (args[0] == "stop")
|
if (args[0] == "stop")
|
||||||
{
|
{
|
||||||
Log.Info("Stopping the service with id '" + d.Id + "'");
|
Log.Info("Stopping the service with id '" + d.Id + "'");
|
||||||
if (s == null) ThrowNoSuchService();
|
if (s == null)
|
||||||
|
ThrowNoSuchService();
|
||||||
|
|
||||||
s.StopService();
|
s.StopService();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (args[0] == "restart")
|
if (args[0] == "restart")
|
||||||
{
|
{
|
||||||
Log.Info("Restarting the service with id '" + d.Id + "'");
|
Log.Info("Restarting the service with id '" + d.Id + "'");
|
||||||
if (s == null)
|
if (s == null)
|
||||||
ThrowNoSuchService();
|
ThrowNoSuchService();
|
||||||
|
|
||||||
if(s.Started)
|
if (s.Started)
|
||||||
s.StopService();
|
s.StopService();
|
||||||
|
|
||||||
while (s.Started)
|
while (s.Started)
|
||||||
|
@ -700,22 +700,24 @@ namespace winsw
|
||||||
s.StartService();
|
s.StartService();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (args[0] == "restart!")
|
if (args[0] == "restart!")
|
||||||
{
|
{
|
||||||
Log.Info("Restarting the service with id '" + d.Id + "'");
|
Log.Info("Restarting the service with id '" + d.Id + "'");
|
||||||
|
|
||||||
// run restart from another process group. see README.md for why this is useful.
|
// run restart from another process group. see README.md for why this is useful.
|
||||||
|
|
||||||
STARTUPINFO si = new STARTUPINFO();
|
STARTUPINFO si = default;
|
||||||
PROCESS_INFORMATION pi = new PROCESS_INFORMATION();
|
|
||||||
|
|
||||||
bool result = Kernel32.CreateProcess(null, d.ExecutablePath+" restart", IntPtr.Zero, IntPtr.Zero, false, 0x200/*CREATE_NEW_PROCESS_GROUP*/, IntPtr.Zero, null, ref si, out pi);
|
bool result = Kernel32.CreateProcess(null, d.ExecutablePath + " restart", IntPtr.Zero, IntPtr.Zero, false, 0x200/*CREATE_NEW_PROCESS_GROUP*/, IntPtr.Zero, null, ref si, out PROCESS_INFORMATION pi);
|
||||||
if (!result)
|
if (!result)
|
||||||
{
|
{
|
||||||
throw new Exception("Failed to invoke restart: "+Marshal.GetLastWin32Error());
|
throw new Exception("Failed to invoke restart: " + Marshal.GetLastWin32Error());
|
||||||
}
|
}
|
||||||
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (args[0] == "status")
|
if (args[0] == "status")
|
||||||
{
|
{
|
||||||
Log.Debug("User requested the status of the process with id '" + d.Id + "'");
|
Log.Debug("User requested the status of the process with id '" + d.Id + "'");
|
||||||
|
@ -727,6 +729,7 @@ namespace winsw
|
||||||
Console.WriteLine("Stopped");
|
Console.WriteLine("Stopped");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (args[0] == "test")
|
if (args[0] == "test")
|
||||||
{
|
{
|
||||||
WrapperService wsvc = new WrapperService(d);
|
WrapperService wsvc = new WrapperService(d);
|
||||||
|
@ -735,6 +738,7 @@ namespace winsw
|
||||||
wsvc.OnStop();
|
wsvc.OnStop();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (args[0] == "testwait")
|
if (args[0] == "testwait")
|
||||||
{
|
{
|
||||||
WrapperService wsvc = new WrapperService(d);
|
WrapperService wsvc = new WrapperService(d);
|
||||||
|
@ -744,12 +748,14 @@ namespace winsw
|
||||||
wsvc.OnStop();
|
wsvc.OnStop();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (args[0] == "help" || args[0] == "--help" || args[0] == "-h"
|
if (args[0] == "help" || args[0] == "--help" || args[0] == "-h"
|
||||||
|| args[0] == "-?" || args[0] == "/?")
|
|| args[0] == "-?" || args[0] == "/?")
|
||||||
{
|
{
|
||||||
printHelp();
|
printHelp();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (args[0] == "version")
|
if (args[0] == "version")
|
||||||
{
|
{
|
||||||
printVersion();
|
printVersion();
|
||||||
|
@ -759,12 +765,12 @@ namespace winsw
|
||||||
Console.WriteLine("Unknown command: " + args[0]);
|
Console.WriteLine("Unknown command: " + args[0]);
|
||||||
printAvailableCommandsInfo();
|
printAvailableCommandsInfo();
|
||||||
throw new Exception("Unknown command: " + args[0]);
|
throw new Exception("Unknown command: " + args[0]);
|
||||||
|
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
Log.Info("Starting ServiceWrapper in the service mode");
|
Log.Info("Starting ServiceWrapper in the service mode");
|
||||||
}
|
}
|
||||||
|
|
||||||
Run(new WrapperService(d));
|
Run(new WrapperService(d));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -851,21 +857,21 @@ namespace winsw
|
||||||
private static void printHelp()
|
private static void printHelp()
|
||||||
{
|
{
|
||||||
Console.WriteLine("A wrapper binary that can be used to host executables as Windows services");
|
Console.WriteLine("A wrapper binary that can be used to host executables as Windows services");
|
||||||
Console.WriteLine("");
|
Console.WriteLine();
|
||||||
Console.WriteLine("Usage: winsw [/redirect file] <command> [<args>]");
|
Console.WriteLine("Usage: winsw [/redirect file] <command> [<args>]");
|
||||||
Console.WriteLine(" Missing arguments trigger the service mode");
|
Console.WriteLine(" Missing arguments trigger the service mode");
|
||||||
Console.WriteLine("");
|
Console.WriteLine();
|
||||||
printAvailableCommandsInfo();
|
printAvailableCommandsInfo();
|
||||||
Console.WriteLine("");
|
Console.WriteLine();
|
||||||
Console.WriteLine("Extra options:");
|
Console.WriteLine("Extra options:");
|
||||||
Console.WriteLine("- '/redirect' - redirect the wrapper's STDOUT and STDERR to the specified file");
|
Console.WriteLine("- '/redirect' - redirect the wrapper's STDOUT and STDERR to the specified file");
|
||||||
Console.WriteLine("");
|
Console.WriteLine();
|
||||||
printVersion();
|
printVersion();
|
||||||
Console.WriteLine("More info: https://github.com/kohsuke/winsw");
|
Console.WriteLine("More info: https://github.com/kohsuke/winsw");
|
||||||
Console.WriteLine("Bug tracker: https://github.com/kohsuke/winsw/issues");
|
Console.WriteLine("Bug tracker: https://github.com/kohsuke/winsw/issues");
|
||||||
}
|
}
|
||||||
|
|
||||||
//TODO: Rework to enum in winsw-2.0
|
// TODO: Rework to enum in winsw-2.0
|
||||||
private static void printAvailableCommandsInfo()
|
private static void printAvailableCommandsInfo()
|
||||||
{
|
{
|
||||||
Console.WriteLine("Available commands:");
|
Console.WriteLine("Available commands:");
|
||||||
|
|
|
@ -16,6 +16,7 @@ namespace winsw
|
||||||
|
|
||||||
[DllImport(KERNEL32)]
|
[DllImport(KERNEL32)]
|
||||||
private static extern bool SetConsoleCtrlHandler(ConsoleCtrlDelegate HandlerRoutine, bool Add);
|
private static extern bool SetConsoleCtrlHandler(ConsoleCtrlDelegate HandlerRoutine, bool Add);
|
||||||
|
|
||||||
// Delegate type to be used as the Handler Routine for SCCH
|
// Delegate type to be used as the Handler Routine for SCCH
|
||||||
private delegate Boolean ConsoleCtrlDelegate(CtrlTypes CtrlType);
|
private delegate Boolean ConsoleCtrlDelegate(CtrlTypes CtrlType);
|
||||||
|
|
||||||
|
@ -43,7 +44,7 @@ namespace winsw
|
||||||
{
|
{
|
||||||
if (AttachConsole((uint)process.Id))
|
if (AttachConsole((uint)process.Id))
|
||||||
{
|
{
|
||||||
//Disable Ctrl-C handling for our program
|
// Disable Ctrl-C handling for our program
|
||||||
SetConsoleCtrlHandler(null, true);
|
SetConsoleCtrlHandler(null, true);
|
||||||
GenerateConsoleCtrlEvent(CtrlTypes.CTRL_C_EVENT, 0);
|
GenerateConsoleCtrlEvent(CtrlTypes.CTRL_C_EVENT, 0);
|
||||||
|
|
||||||
|
|
|
@ -3,7 +3,6 @@ using System.Collections.Generic;
|
||||||
using System.Diagnostics;
|
using System.Diagnostics;
|
||||||
using System.IO;
|
using System.IO;
|
||||||
using System.Reflection;
|
using System.Reflection;
|
||||||
using System.Text;
|
|
||||||
using System.Xml;
|
using System.Xml;
|
||||||
using WMI;
|
using WMI;
|
||||||
|
|
||||||
|
@ -14,11 +13,11 @@ namespace winsw.Configuration
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public sealed class DefaultWinSWSettings : IWinSWConfiguration
|
public sealed class DefaultWinSWSettings : IWinSWConfiguration
|
||||||
{
|
{
|
||||||
public string Id { get { return null; } }
|
public string Id => null;
|
||||||
public string Caption { get { return null; } }
|
public string Caption => null;
|
||||||
public string Description { get { return null; } }
|
public string Description => null;
|
||||||
public string Executable { get { return null; } }
|
public string Executable => null;
|
||||||
public bool HideWindow { get { return false; } }
|
public bool HideWindow => false;
|
||||||
|
|
||||||
public string ExecutablePath
|
public string ExecutablePath
|
||||||
{
|
{
|
||||||
|
@ -32,47 +31,47 @@ namespace winsw.Configuration
|
||||||
}
|
}
|
||||||
|
|
||||||
// Installation
|
// Installation
|
||||||
public bool AllowServiceAcountLogonRight { get { return false; } }
|
public bool AllowServiceAcountLogonRight => false;
|
||||||
public string ServiceAccountPassword { get { return null; } }
|
public string ServiceAccountPassword => null;
|
||||||
public string ServiceAccountUser { get { return "NULL\\NULL"; } }
|
public string ServiceAccountUser => "NULL\\NULL";
|
||||||
public List<winsw.Native.SC_ACTION> FailureActions { get { return new List<winsw.Native.SC_ACTION>(); } }
|
public List<Native.SC_ACTION> FailureActions => new List<Native.SC_ACTION>();
|
||||||
public TimeSpan ResetFailureAfter { get { return TimeSpan.FromDays(1); } }
|
public TimeSpan ResetFailureAfter => TimeSpan.FromDays(1);
|
||||||
|
|
||||||
// Executable management
|
// Executable management
|
||||||
public string Arguments { get { return ""; } }
|
public string Arguments => string.Empty;
|
||||||
public string Startarguments { get { return null; } }
|
public string Startarguments => null;
|
||||||
public string StopExecutable { get { return null; } }
|
public string StopExecutable => null;
|
||||||
public string Stoparguments { get { return null; } }
|
public string Stoparguments => null;
|
||||||
public string WorkingDirectory { get { return Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location); } }
|
public string WorkingDirectory => Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location);
|
||||||
public ProcessPriorityClass Priority { get { return ProcessPriorityClass.Normal; } }
|
public ProcessPriorityClass Priority => ProcessPriorityClass.Normal;
|
||||||
public TimeSpan StopTimeout { get { return TimeSpan.FromSeconds(15); } }
|
public TimeSpan StopTimeout => TimeSpan.FromSeconds(15);
|
||||||
public bool StopParentProcessFirst { get { return false; } }
|
public bool StopParentProcessFirst => false;
|
||||||
|
|
||||||
// Service management
|
// Service management
|
||||||
public StartMode StartMode { get { return StartMode.Automatic; } }
|
public StartMode StartMode => StartMode.Automatic;
|
||||||
public bool DelayedAutoStart { get { return false; } }
|
public bool DelayedAutoStart => false;
|
||||||
public string[] ServiceDependencies { get { return new string[0]; } }
|
public string[] ServiceDependencies => new string[0];
|
||||||
public TimeSpan WaitHint { get { return TimeSpan.FromSeconds(15); } }
|
public TimeSpan WaitHint => TimeSpan.FromSeconds(15);
|
||||||
public TimeSpan SleepTime { get { return TimeSpan.FromSeconds(1); } }
|
public TimeSpan SleepTime => TimeSpan.FromSeconds(1);
|
||||||
public bool Interactive { get { return false; } }
|
public bool Interactive => false;
|
||||||
|
|
||||||
// Logging
|
// Logging
|
||||||
public string LogDirectory { get { return Path.GetDirectoryName(ExecutablePath); } }
|
public string LogDirectory => Path.GetDirectoryName(ExecutablePath);
|
||||||
public string LogMode { get { return "append"; } }
|
public string LogMode => "append";
|
||||||
|
|
||||||
public bool OutFileDisabled { get { return false; } }
|
public bool OutFileDisabled => false;
|
||||||
public bool ErrFileDisabled { get { return false; } }
|
public bool ErrFileDisabled => false;
|
||||||
public string OutFilePattern { get { return ".out.log"; } }
|
public string OutFilePattern => ".out.log";
|
||||||
public string ErrFilePattern { get { return ".err.log"; } }
|
public string ErrFilePattern => ".err.log";
|
||||||
|
|
||||||
// Environment
|
// Environment
|
||||||
public List<Download> Downloads { get { return new List<Download>(); } }
|
public List<Download> Downloads => new List<Download>();
|
||||||
public Dictionary<string, string> EnvironmentVariables { get { return new Dictionary<string, string>(); } }
|
public Dictionary<string, string> EnvironmentVariables => new Dictionary<string, string>();
|
||||||
|
|
||||||
// Misc
|
// Misc
|
||||||
public bool BeepOnShutdown { get { return false; } }
|
public bool BeepOnShutdown => false;
|
||||||
|
|
||||||
// Extensions
|
// Extensions
|
||||||
public XmlNode ExtensionsConfiguration { get {return null; } }
|
public XmlNode ExtensionsConfiguration => null;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -7,7 +7,7 @@ namespace winsw.Configuration
|
||||||
{
|
{
|
||||||
public interface IWinSWConfiguration
|
public interface IWinSWConfiguration
|
||||||
{
|
{
|
||||||
//TODO: Document the parameters && refactor
|
// TODO: Document the parameters && refactor
|
||||||
|
|
||||||
string Id { get; }
|
string Id { get; }
|
||||||
string Caption { get; }
|
string Caption { get; }
|
||||||
|
@ -20,7 +20,7 @@ namespace winsw.Configuration
|
||||||
bool AllowServiceAcountLogonRight { get; }
|
bool AllowServiceAcountLogonRight { get; }
|
||||||
string ServiceAccountPassword { get; }
|
string ServiceAccountPassword { get; }
|
||||||
string ServiceAccountUser { get; }
|
string ServiceAccountUser { get; }
|
||||||
List<winsw.Native.SC_ACTION> FailureActions { get; }
|
List<Native.SC_ACTION> FailureActions { get; }
|
||||||
TimeSpan ResetFailureAfter { get; }
|
TimeSpan ResetFailureAfter { get; }
|
||||||
|
|
||||||
// Executable management
|
// Executable management
|
||||||
|
@ -42,7 +42,7 @@ namespace winsw.Configuration
|
||||||
|
|
||||||
// Logging
|
// Logging
|
||||||
string LogDirectory { get; }
|
string LogDirectory { get; }
|
||||||
//TODO: replace by enum
|
// TODO: replace by enum
|
||||||
string LogMode { get; }
|
string LogMode { get; }
|
||||||
|
|
||||||
// Environment
|
// Environment
|
||||||
|
|
|
@ -13,7 +13,12 @@ namespace winsw
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public class Download
|
public class Download
|
||||||
{
|
{
|
||||||
public enum AuthType { none = 0, sspi, basic }
|
public enum AuthType
|
||||||
|
{
|
||||||
|
none = 0,
|
||||||
|
sspi,
|
||||||
|
basic
|
||||||
|
}
|
||||||
|
|
||||||
public readonly string From;
|
public readonly string From;
|
||||||
public readonly string To;
|
public readonly string To;
|
||||||
|
@ -23,10 +28,16 @@ namespace winsw
|
||||||
public readonly bool UnsecureAuth;
|
public readonly bool UnsecureAuth;
|
||||||
public readonly bool FailOnError;
|
public readonly bool FailOnError;
|
||||||
|
|
||||||
public string ShortId { get { return String.Format("(download from {0})", From); } }
|
public string ShortId => $"(download from {From})";
|
||||||
|
|
||||||
public Download(string from, string to, bool failOnError = false, AuthType auth = AuthType.none,
|
public Download(
|
||||||
string username = null, string password = null, bool unsecureAuth = false)
|
string from,
|
||||||
|
string to,
|
||||||
|
bool failOnError = false,
|
||||||
|
AuthType auth = AuthType.none,
|
||||||
|
string username = null,
|
||||||
|
string password = null,
|
||||||
|
bool unsecureAuth = false)
|
||||||
{
|
{
|
||||||
From = from;
|
From = from;
|
||||||
To = to;
|
To = to;
|
||||||
|
@ -48,12 +59,12 @@ namespace winsw
|
||||||
To = XmlHelper.SingleAttribute<String>(n, "to");
|
To = XmlHelper.SingleAttribute<String>(n, "to");
|
||||||
|
|
||||||
// All arguments below are optional
|
// All arguments below are optional
|
||||||
FailOnError = XmlHelper.SingleAttribute<bool>(n, "failOnError", false);
|
FailOnError = XmlHelper.SingleAttribute(n, "failOnError", false);
|
||||||
|
|
||||||
Auth = XmlHelper.EnumAttribute<AuthType>(n, "auth", AuthType.none);
|
Auth = XmlHelper.EnumAttribute(n, "auth", AuthType.none);
|
||||||
Username = XmlHelper.SingleAttribute<String>(n, "user", null);
|
Username = XmlHelper.SingleAttribute<String>(n, "user", null);
|
||||||
Password = XmlHelper.SingleAttribute<String>(n, "password", null);
|
Password = XmlHelper.SingleAttribute<String>(n, "password", null);
|
||||||
UnsecureAuth = XmlHelper.SingleAttribute<bool>(n, "unsecureAuth", false);
|
UnsecureAuth = XmlHelper.SingleAttribute(n, "unsecureAuth", false);
|
||||||
|
|
||||||
if (Auth == AuthType.basic)
|
if (Auth == AuthType.basic)
|
||||||
{
|
{
|
||||||
|
@ -69,6 +80,7 @@ namespace winsw
|
||||||
{
|
{
|
||||||
throw new InvalidDataException("Basic Auth is enabled, but username is not specified " + ShortId);
|
throw new InvalidDataException("Basic Auth is enabled, but username is not specified " + ShortId);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (Password == null)
|
if (Password == null)
|
||||||
{
|
{
|
||||||
throw new InvalidDataException("Basic Auth is enabled, but password is not specified " + ShortId);
|
throw new InvalidDataException("Basic Auth is enabled, but password is not specified " + ShortId);
|
||||||
|
@ -87,7 +99,7 @@ namespace winsw
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Downloads the requested file and puts it to the specified target.
|
/// Downloads the requested file and puts it to the specified target.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <exception cref="System.Net.WebException">
|
/// <exception cref="WebException">
|
||||||
/// Download failure. FailOnError flag should be processed outside.
|
/// Download failure. FailOnError flag should be processed outside.
|
||||||
/// </exception>
|
/// </exception>
|
||||||
public void Perform()
|
public void Perform()
|
||||||
|
@ -120,6 +132,7 @@ namespace winsw
|
||||||
// only after we successfully downloaded a file, overwrite the existing one
|
// only after we successfully downloaded a file, overwrite the existing one
|
||||||
if (File.Exists(To))
|
if (File.Exists(To))
|
||||||
File.Delete(To);
|
File.Delete(To);
|
||||||
|
|
||||||
File.Move(To + ".tmp", To);
|
File.Move(To + ".tmp", To);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -129,9 +142,12 @@ namespace winsw
|
||||||
while (true)
|
while (true)
|
||||||
{
|
{
|
||||||
int len = i.Read(buf, 0, buf.Length);
|
int len = i.Read(buf, 0, buf.Length);
|
||||||
if (len <= 0) break;
|
if (len <= 0)
|
||||||
|
break;
|
||||||
|
|
||||||
o.Write(buf, 0, len);
|
o.Write(buf, 0, len);
|
||||||
}
|
}
|
||||||
|
|
||||||
i.Close();
|
i.Close();
|
||||||
o.Close();
|
o.Close();
|
||||||
}
|
}
|
||||||
|
|
|
@ -200,9 +200,8 @@ namespace DynamicProxy
|
||||||
FieldBuilder handlerField = typeBuilder.DefineField(
|
FieldBuilder handlerField = typeBuilder.DefineField(
|
||||||
HANDLER_NAME, handlerType, FieldAttributes.Private);
|
HANDLER_NAME, handlerType, FieldAttributes.Private);
|
||||||
|
|
||||||
|
|
||||||
// build a constructor that takes the delegate object as the only argument
|
// build a constructor that takes the delegate object as the only argument
|
||||||
//ConstructorInfo defaultObjConstructor = objType.GetConstructor( new Type[0] );
|
// ConstructorInfo defaultObjConstructor = objType.GetConstructor( new Type[0] );
|
||||||
ConstructorInfo superConstructor = objType.GetConstructor(new Type[0]);
|
ConstructorInfo superConstructor = objType.GetConstructor(new Type[0]);
|
||||||
ConstructorBuilder delegateConstructor = typeBuilder.DefineConstructor(
|
ConstructorBuilder delegateConstructor = typeBuilder.DefineConstructor(
|
||||||
MethodAttributes.Public, CallingConventions.Standard, new Type[] { handlerType });
|
MethodAttributes.Public, CallingConventions.Standard, new Type[] { handlerType });
|
||||||
|
@ -242,106 +241,122 @@ namespace DynamicProxy
|
||||||
private static readonly MethodInfo INVOKE_METHOD = typeof(IProxyInvocationHandler).GetMethod("Invoke");
|
private static readonly MethodInfo INVOKE_METHOD = typeof(IProxyInvocationHandler).GetMethod("Invoke");
|
||||||
private static readonly MethodInfo GET_METHODINFO_METHOD = typeof(MetaDataFactory).GetMethod("GetMethod", new Type[] { typeof(string), typeof(int) });
|
private static readonly MethodInfo GET_METHODINFO_METHOD = typeof(MetaDataFactory).GetMethod("GetMethod", new Type[] { typeof(string), typeof(int) });
|
||||||
|
|
||||||
private void GenerateMethod( Type interfaceType, FieldBuilder handlerField, TypeBuilder typeBuilder ) {
|
private void GenerateMethod(Type interfaceType, FieldBuilder handlerField, TypeBuilder typeBuilder)
|
||||||
MetaDataFactory.Add( interfaceType );
|
{
|
||||||
|
MetaDataFactory.Add(interfaceType);
|
||||||
MethodInfo[] interfaceMethods = interfaceType.GetMethods();
|
MethodInfo[] interfaceMethods = interfaceType.GetMethods();
|
||||||
PropertyInfo[] props = interfaceType.GetProperties();
|
PropertyInfo[] props = interfaceType.GetProperties();
|
||||||
|
|
||||||
for ( int i = 0; i < interfaceMethods.Length; i++ ) {
|
for (int i = 0; i < interfaceMethods.Length; i++)
|
||||||
|
{
|
||||||
MethodInfo methodInfo = interfaceMethods[i];
|
MethodInfo methodInfo = interfaceMethods[i];
|
||||||
|
|
||||||
// Get the method parameters since we need to create an array
|
// Get the method parameters since we need to create an array
|
||||||
// of parameter types
|
// of parameter types
|
||||||
ParameterInfo[] methodParams = methodInfo.GetParameters();
|
ParameterInfo[] methodParams = methodInfo.GetParameters();
|
||||||
int numOfParams = methodParams.Length;
|
int numOfParams = methodParams.Length;
|
||||||
Type[] methodParameters = new Type[ numOfParams ];
|
Type[] methodParameters = new Type[numOfParams];
|
||||||
|
|
||||||
// convert the ParameterInfo objects into Type
|
// convert the ParameterInfo objects into Type
|
||||||
for ( int j = 0; j < numOfParams; j++ ) {
|
for (int j = 0; j < numOfParams; j++)
|
||||||
|
{
|
||||||
methodParameters[j] = methodParams[j].ParameterType;
|
methodParameters[j] = methodParams[j].ParameterType;
|
||||||
}
|
}
|
||||||
|
|
||||||
// create a new builder for the method in the interface
|
// create a new builder for the method in the interface
|
||||||
MethodBuilder methodBuilder = typeBuilder.DefineMethod(
|
MethodBuilder methodBuilder = typeBuilder.DefineMethod(
|
||||||
methodInfo.Name,
|
methodInfo.Name,
|
||||||
/*MethodAttributes.Public | MethodAttributes.Virtual | */ methodInfo.Attributes&~MethodAttributes.Abstract,
|
/*MethodAttributes.Public | MethodAttributes.Virtual | */ methodInfo.Attributes & ~MethodAttributes.Abstract,
|
||||||
CallingConventions.Standard,
|
CallingConventions.Standard,
|
||||||
methodInfo.ReturnType, methodParameters );
|
methodInfo.ReturnType, methodParameters);
|
||||||
|
|
||||||
#region( "Handler Method IL Code" )
|
#region( "Handler Method IL Code" )
|
||||||
ILGenerator methodIL = methodBuilder.GetILGenerator();
|
ILGenerator methodIL = methodBuilder.GetILGenerator();
|
||||||
|
|
||||||
// load "this"
|
// load "this"
|
||||||
methodIL.Emit( OpCodes.Ldarg_0 );
|
methodIL.Emit(OpCodes.Ldarg_0);
|
||||||
// load the handler
|
// load the handler
|
||||||
methodIL.Emit( OpCodes.Ldfld, handlerField );
|
methodIL.Emit(OpCodes.Ldfld, handlerField);
|
||||||
// load "this" since its needed for the call to invoke
|
// load "this" since its needed for the call to invoke
|
||||||
methodIL.Emit( OpCodes.Ldarg_0 );
|
methodIL.Emit(OpCodes.Ldarg_0);
|
||||||
// load the name of the interface, used to get the MethodInfo object
|
// load the name of the interface, used to get the MethodInfo object
|
||||||
// from MetaDataFactory
|
// from MetaDataFactory
|
||||||
methodIL.Emit( OpCodes.Ldstr, interfaceType.FullName );
|
methodIL.Emit(OpCodes.Ldstr, interfaceType.FullName);
|
||||||
// load the index, used to get the MethodInfo object
|
// load the index, used to get the MethodInfo object
|
||||||
// from MetaDataFactory
|
// from MetaDataFactory
|
||||||
methodIL.Emit( OpCodes.Ldc_I4, i );
|
methodIL.Emit(OpCodes.Ldc_I4, i);
|
||||||
// invoke GetMethod in MetaDataFactory
|
// invoke GetMethod in MetaDataFactory
|
||||||
methodIL.Emit( OpCodes.Call, GET_METHODINFO_METHOD);
|
methodIL.Emit(OpCodes.Call, GET_METHODINFO_METHOD);
|
||||||
|
|
||||||
// load the number of parameters onto the stack
|
// load the number of parameters onto the stack
|
||||||
methodIL.Emit( OpCodes.Ldc_I4, numOfParams );
|
methodIL.Emit(OpCodes.Ldc_I4, numOfParams);
|
||||||
// create a new array, using the size that was just pused on the stack
|
// create a new array, using the size that was just pused on the stack
|
||||||
methodIL.Emit( OpCodes.Newarr, typeof(object) );
|
methodIL.Emit(OpCodes.Newarr, typeof(object));
|
||||||
|
|
||||||
// if we have any parameters, then iterate through and set the values
|
// if we have any parameters, then iterate through and set the values
|
||||||
// of each element to the corresponding arguments
|
// of each element to the corresponding arguments
|
||||||
for ( int j = 0; j < numOfParams; j++ ) {
|
for (int j = 0; j < numOfParams; j++)
|
||||||
methodIL.Emit( OpCodes.Dup ); // this copies the array
|
{
|
||||||
methodIL.Emit( OpCodes.Ldc_I4, j );
|
methodIL.Emit(OpCodes.Dup); // this copies the array
|
||||||
methodIL.Emit( OpCodes.Ldarg, j + 1 );
|
methodIL.Emit(OpCodes.Ldc_I4, j);
|
||||||
if ( methodParameters[j].IsValueType ) {
|
methodIL.Emit(OpCodes.Ldarg, j + 1);
|
||||||
methodIL.Emit( OpCodes.Box, methodParameters[j] );
|
if (methodParameters[j].IsValueType)
|
||||||
|
{
|
||||||
|
methodIL.Emit(OpCodes.Box, methodParameters[j]);
|
||||||
}
|
}
|
||||||
methodIL.Emit( OpCodes.Stelem_Ref );
|
|
||||||
|
methodIL.Emit(OpCodes.Stelem_Ref);
|
||||||
}
|
}
|
||||||
|
|
||||||
// call the Invoke method
|
// call the Invoke method
|
||||||
methodIL.Emit( OpCodes.Callvirt, INVOKE_METHOD );
|
methodIL.Emit(OpCodes.Callvirt, INVOKE_METHOD);
|
||||||
|
|
||||||
if ( methodInfo.ReturnType != typeof(void) ) {
|
if (methodInfo.ReturnType != typeof(void))
|
||||||
|
{
|
||||||
// if the return type if a value type, then unbox the return value
|
// if the return type if a value type, then unbox the return value
|
||||||
// so that we don't get junk.
|
// so that we don't get junk.
|
||||||
if ( methodInfo.ReturnType.IsValueType ) {
|
if (methodInfo.ReturnType.IsValueType)
|
||||||
methodIL.Emit( OpCodes.Unbox, methodInfo.ReturnType );
|
{
|
||||||
if ( methodInfo.ReturnType.IsEnum ) {
|
methodIL.Emit(OpCodes.Unbox, methodInfo.ReturnType);
|
||||||
methodIL.Emit( OpCodes.Ldind_I4 );
|
if (methodInfo.ReturnType.IsEnum)
|
||||||
} else if ( !methodInfo.ReturnType.IsPrimitive ) {
|
{
|
||||||
methodIL.Emit( OpCodes.Ldobj, methodInfo.ReturnType );
|
methodIL.Emit(OpCodes.Ldind_I4);
|
||||||
} else {
|
}
|
||||||
methodIL.Emit( (OpCode) OpCodeTypeMapper[ methodInfo.ReturnType ] );
|
else if (!methodInfo.ReturnType.IsPrimitive)
|
||||||
|
{
|
||||||
|
methodIL.Emit(OpCodes.Ldobj, methodInfo.ReturnType);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
methodIL.Emit((OpCode)OpCodeTypeMapper[methodInfo.ReturnType]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else {
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
// pop the return value that Invoke returned from the stack since
|
// pop the return value that Invoke returned from the stack since
|
||||||
// the method's return type is void.
|
// the method's return type is void.
|
||||||
methodIL.Emit( OpCodes.Pop );
|
methodIL.Emit(OpCodes.Pop);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Return
|
// Return
|
||||||
methodIL.Emit( OpCodes.Ret );
|
methodIL.Emit(OpCodes.Ret);
|
||||||
#endregion
|
#endregion
|
||||||
}
|
}
|
||||||
|
|
||||||
//for (int i = 0; i < props.Length; i++)
|
// for (int i = 0; i < props.Length; i++)
|
||||||
//{
|
// {
|
||||||
// PropertyInfo p = props[i];
|
// PropertyInfo p = props[i];
|
||||||
|
|
||||||
// PropertyBuilder pb = typeBuilder.DefineProperty(p.Name, p.Attributes, p.PropertyType, new Type[] { p.PropertyType });
|
// PropertyBuilder pb = typeBuilder.DefineProperty(p.Name, p.Attributes, p.PropertyType, new Type[] { p.PropertyType });
|
||||||
// pb.SetGetMethod((MethodBuilder)methodTable[p.GetGetMethod()]);
|
// pb.SetGetMethod((MethodBuilder)methodTable[p.GetGetMethod()]);
|
||||||
// pb.SetSetMethod((MethodBuilder)methodTable[p.GetSetMethod()]);
|
// pb.SetSetMethod((MethodBuilder)methodTable[p.GetSetMethod()]);
|
||||||
//}
|
// }
|
||||||
|
|
||||||
// Iterate through the parent interfaces and recursively call this method
|
// Iterate through the parent interfaces and recursively call this method
|
||||||
foreach ( Type parentType in interfaceType.GetInterfaces() ) {
|
foreach (Type parentType in interfaceType.GetInterfaces())
|
||||||
GenerateMethod( parentType, handlerField, typeBuilder );
|
{
|
||||||
|
GenerateMethod(parentType, handlerField, typeBuilder);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,12 +1,12 @@
|
||||||
using System;
|
using System;
|
||||||
using System.Xml;
|
using System.Xml;
|
||||||
using winsw.Util;
|
|
||||||
|
|
||||||
namespace winsw.Extensions
|
namespace winsw.Extensions
|
||||||
{
|
{
|
||||||
public abstract class AbstractWinSWExtension : IWinSWExtension
|
public abstract class AbstractWinSWExtension : IWinSWExtension
|
||||||
{
|
{
|
||||||
public abstract String DisplayName { get; }
|
public abstract String DisplayName { get; }
|
||||||
|
|
||||||
public WinSWExtensionDescriptor Descriptor { get; set; }
|
public WinSWExtensionDescriptor Descriptor { get; set; }
|
||||||
|
|
||||||
public virtual void Configure(ServiceDescriptor descriptor, XmlNode node)
|
public virtual void Configure(ServiceDescriptor descriptor, XmlNode node)
|
||||||
|
|
|
@ -18,12 +18,6 @@ namespace winsw.Extensions
|
||||||
ExtensionId = extensionName;
|
ExtensionId = extensionName;
|
||||||
}
|
}
|
||||||
|
|
||||||
public override string Message
|
public override string Message => ExtensionId + ": " + base.Message;
|
||||||
{
|
|
||||||
get
|
|
||||||
{
|
|
||||||
return ExtensionId + ": " + base.Message;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,8 +1,4 @@
|
||||||
using System;
|
namespace winsw.Extensions
|
||||||
using System.Collections.Generic;
|
|
||||||
using System.Text;
|
|
||||||
|
|
||||||
namespace winsw.Extensions
|
|
||||||
{
|
{
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// This attribute is used to identify extension points within the code
|
/// This attribute is used to identify extension points within the code
|
||||||
|
|
|
@ -1,6 +1,5 @@
|
||||||
using System;
|
using System;
|
||||||
using System.Xml;
|
using System.Xml;
|
||||||
using winsw.Util;
|
|
||||||
|
|
||||||
namespace winsw.Extensions
|
namespace winsw.Extensions
|
||||||
{
|
{
|
||||||
|
|
|
@ -1,17 +1,16 @@
|
||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Xml;
|
|
||||||
using System.Reflection;
|
using System.Reflection;
|
||||||
using System.Diagnostics;
|
using System.Xml;
|
||||||
using winsw.Util;
|
|
||||||
using log4net;
|
using log4net;
|
||||||
|
|
||||||
namespace winsw.Extensions
|
namespace winsw.Extensions
|
||||||
{
|
{
|
||||||
public class WinSWExtensionManager
|
public class WinSWExtensionManager
|
||||||
{
|
{
|
||||||
public Dictionary<string, IWinSWExtension> Extensions { private set; get; }
|
public Dictionary<string, IWinSWExtension> Extensions { get; private set; }
|
||||||
public ServiceDescriptor ServiceDescriptor { private set; get; }
|
|
||||||
|
public ServiceDescriptor ServiceDescriptor { get; private set; }
|
||||||
|
|
||||||
private static readonly ILog Log = LogManager.GetLogger(typeof(WinSWExtensionManager));
|
private static readonly ILog Log = LogManager.GetLogger(typeof(WinSWExtensionManager));
|
||||||
|
|
||||||
|
@ -100,10 +99,9 @@ namespace winsw.Extensions
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
//TODO: Implement loading of external extensions. Current version supports internal hack
|
// TODO: Implement loading of external extensions. Current version supports internal hack
|
||||||
#region Extension load management
|
#region Extension load management
|
||||||
|
|
||||||
|
|
||||||
/// Loads extensions according to the configuration file.
|
/// Loads extensions according to the configuration file.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="logger">Logger</param>
|
/// <param name="logger">Logger</param>
|
||||||
|
@ -131,7 +129,7 @@ namespace winsw.Extensions
|
||||||
}
|
}
|
||||||
|
|
||||||
var extensionsConfig = ServiceDescriptor.ExtensionsConfiguration;
|
var extensionsConfig = ServiceDescriptor.ExtensionsConfiguration;
|
||||||
XmlElement configNode =(extensionsConfig != null) ? extensionsConfig.SelectSingleNode("extension[@id='"+id+"'][1]") as XmlElement : null;
|
XmlElement configNode = (extensionsConfig != null) ? extensionsConfig.SelectSingleNode("extension[@id='" + id + "'][1]") as XmlElement : null;
|
||||||
if (configNode == null)
|
if (configNode == null)
|
||||||
{
|
{
|
||||||
throw new ExtensionException(id, "Cannot get the configuration entry");
|
throw new ExtensionException(id, "Cannot get the configuration entry");
|
||||||
|
@ -151,6 +149,7 @@ namespace winsw.Extensions
|
||||||
Log.Fatal("Failed to configure the extension " + id, ex);
|
Log.Fatal("Failed to configure the extension " + id, ex);
|
||||||
throw ex;
|
throw ex;
|
||||||
}
|
}
|
||||||
|
|
||||||
Extensions.Add(id, extension);
|
Extensions.Add(id, extension);
|
||||||
Log.Info("Extension loaded: " + id);
|
Log.Info("Extension loaded: " + id);
|
||||||
}
|
}
|
||||||
|
@ -158,7 +157,6 @@ namespace winsw.Extensions
|
||||||
{
|
{
|
||||||
Log.Warn("Extension is disabled: " + id);
|
Log.Warn("Extension is disabled: " + id);
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private IWinSWExtension CreateExtensionInstance(string id, string className)
|
private IWinSWExtension CreateExtensionInstance(string id, string className)
|
||||||
|
@ -172,20 +170,21 @@ namespace winsw.Extensions
|
||||||
Type t = Type.GetType(className);
|
Type t = Type.GetType(className);
|
||||||
if (t == null)
|
if (t == null)
|
||||||
{
|
{
|
||||||
throw new ExtensionException(id, "Class "+className+" does not exist");
|
throw new ExtensionException(id, "Class " + className + " does not exist");
|
||||||
}
|
}
|
||||||
|
|
||||||
created = Activator.CreateInstance(t);
|
created = Activator.CreateInstance(t);
|
||||||
}
|
}
|
||||||
catch (Exception ex)
|
catch (Exception ex)
|
||||||
{
|
{
|
||||||
throw new ExtensionException(id, "Cannot load the class by name: "+className, ex);
|
throw new ExtensionException(id, "Cannot load the class by name: " + className, ex);
|
||||||
}
|
}
|
||||||
|
|
||||||
var extension = created as IWinSWExtension;
|
if (!(created is IWinSWExtension extension))
|
||||||
if (extension == null)
|
|
||||||
{
|
{
|
||||||
throw new ExtensionException(id, "The loaded class is not a WinSW extension: " + className + ". Type is " + created.GetType());
|
throw new ExtensionException(id, "The loaded class is not a WinSW extension: " + className + ". Type is " + created.GetType());
|
||||||
}
|
}
|
||||||
|
|
||||||
return extension;
|
return extension;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -2,7 +2,6 @@ using System;
|
||||||
using System.Diagnostics;
|
using System.Diagnostics;
|
||||||
using System.IO;
|
using System.IO;
|
||||||
using System.Threading;
|
using System.Threading;
|
||||||
using System.Timers;
|
|
||||||
using ICSharpCode.SharpZipLib.Zip;
|
using ICSharpCode.SharpZipLib.Zip;
|
||||||
|
|
||||||
namespace winsw
|
namespace winsw
|
||||||
|
@ -11,6 +10,7 @@ namespace winsw
|
||||||
public interface EventLogger
|
public interface EventLogger
|
||||||
{
|
{
|
||||||
void LogEvent(string message);
|
void LogEvent(string message);
|
||||||
|
|
||||||
void LogEvent(string message, EventLogEntryType type);
|
void LogEvent(string message, EventLogEntryType type);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -25,7 +25,7 @@ namespace winsw
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Error and information about logging should be reported here.
|
/// Error and information about logging should be reported here.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public EventLogger EventLogger { set; get; }
|
public EventLogger EventLogger { get; set; }
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Convenience method to copy stuff from StreamReader to StreamWriter
|
/// Convenience method to copy stuff from StreamReader to StreamWriter
|
||||||
|
@ -36,10 +36,13 @@ namespace winsw
|
||||||
while (true)
|
while (true)
|
||||||
{
|
{
|
||||||
int sz = i.Read(buf, 0, buf.Length);
|
int sz = i.Read(buf, 0, buf.Length);
|
||||||
if (sz == 0) break;
|
if (sz == 0)
|
||||||
|
break;
|
||||||
|
|
||||||
o.Write(buf, 0, sz);
|
o.Write(buf, 0, sz);
|
||||||
o.Flush();
|
o.Flush();
|
||||||
}
|
}
|
||||||
|
|
||||||
i.Close();
|
i.Close();
|
||||||
o.Close();
|
o.Close();
|
||||||
}
|
}
|
||||||
|
@ -66,11 +69,11 @@ namespace winsw
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public abstract class AbstractFileLogAppender : LogHandler
|
public abstract class AbstractFileLogAppender : LogHandler
|
||||||
{
|
{
|
||||||
protected string BaseLogFileName { private set; get; }
|
protected string BaseLogFileName { get; private set; }
|
||||||
protected bool OutFileDisabled { private set; get; }
|
protected bool OutFileDisabled { get; private set; }
|
||||||
protected bool ErrFileDisabled { private set; get; }
|
protected bool ErrFileDisabled { get; private set; }
|
||||||
protected string OutFilePattern { private set; get; }
|
protected string OutFilePattern { get; private set; }
|
||||||
protected string ErrFilePattern { private set; get; }
|
protected string ErrFilePattern { get; private set; }
|
||||||
|
|
||||||
protected AbstractFileLogAppender(string logDirectory, string baseName, bool outFileDisabled, bool errFileDisabled, string outFilePattern, string errFilePattern)
|
protected AbstractFileLogAppender(string logDirectory, string baseName, bool outFileDisabled, bool errFileDisabled, string outFilePattern, string errFilePattern)
|
||||||
{
|
{
|
||||||
|
@ -84,9 +87,9 @@ namespace winsw
|
||||||
|
|
||||||
public abstract class SimpleLogAppender : AbstractFileLogAppender
|
public abstract class SimpleLogAppender : AbstractFileLogAppender
|
||||||
{
|
{
|
||||||
public FileMode FileMode { private set; get; }
|
public FileMode FileMode { get; private set; }
|
||||||
public string OutputLogFileName { private set; get; }
|
public string OutputLogFileName { get; private set; }
|
||||||
public string ErrorLogFileName { private set; get; }
|
public string ErrorLogFileName { get; private set; }
|
||||||
|
|
||||||
protected SimpleLogAppender(string logDirectory, string baseName, FileMode fileMode, bool outFileDisabled, bool errFileDisabled, string outFilePattern, string errFilePattern)
|
protected SimpleLogAppender(string logDirectory, string baseName, FileMode fileMode, bool outFileDisabled, bool errFileDisabled, string outFilePattern, string errFilePattern)
|
||||||
: base(logDirectory, baseName, outFileDisabled, errFileDisabled, outFilePattern, errFilePattern)
|
: base(logDirectory, baseName, outFileDisabled, errFileDisabled, outFilePattern, errFilePattern)
|
||||||
|
@ -98,8 +101,11 @@ namespace winsw
|
||||||
|
|
||||||
public override void log(Stream outputStream, Stream errorStream)
|
public override void log(Stream outputStream, Stream errorStream)
|
||||||
{
|
{
|
||||||
if (!OutFileDisabled) new Thread(delegate() { CopyStream(outputStream, new FileStream(OutputLogFileName, FileMode)); }).Start();
|
if (!OutFileDisabled)
|
||||||
if (!ErrFileDisabled) new Thread(delegate() { CopyStream(errorStream, new FileStream(ErrorLogFileName, FileMode)); }).Start();
|
new Thread(() => CopyStream(outputStream, new FileStream(OutputLogFileName, FileMode))).Start();
|
||||||
|
|
||||||
|
if (!ErrFileDisabled)
|
||||||
|
new Thread(() => CopyStream(errorStream, new FileStream(ErrorLogFileName, FileMode))).Start();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -126,8 +132,8 @@ namespace winsw
|
||||||
{
|
{
|
||||||
public override void log(Stream outputStream, Stream errorStream)
|
public override void log(Stream outputStream, Stream errorStream)
|
||||||
{
|
{
|
||||||
new Thread(delegate() { CopyStream(outputStream, Stream.Null); }).Start();
|
new Thread(() => CopyStream(outputStream, Stream.Null)).Start();
|
||||||
new Thread(delegate() { CopyStream(errorStream, Stream.Null); }).Start();
|
new Thread(() => CopyStream(errorStream, Stream.Null)).Start();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -145,8 +151,11 @@ namespace winsw
|
||||||
|
|
||||||
public override void log(Stream outputStream, Stream errorStream)
|
public override void log(Stream outputStream, Stream errorStream)
|
||||||
{
|
{
|
||||||
if (!OutFileDisabled) new Thread(delegate() { CopyStreamWithDateRotation(outputStream, OutFilePattern); }).Start();
|
if (!OutFileDisabled)
|
||||||
if (!ErrFileDisabled) new Thread(delegate() { CopyStreamWithDateRotation(errorStream, ErrFilePattern); }).Start();
|
new Thread(() => CopyStreamWithDateRotation(outputStream, OutFilePattern)).Start();
|
||||||
|
|
||||||
|
if (!ErrFileDisabled)
|
||||||
|
new Thread(() => CopyStreamWithDateRotation(errorStream, ErrFilePattern)).Start();
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
|
@ -162,16 +171,19 @@ namespace winsw
|
||||||
while (true)
|
while (true)
|
||||||
{
|
{
|
||||||
int len = data.Read(buf, 0, buf.Length);
|
int len = data.Read(buf, 0, buf.Length);
|
||||||
if (len == 0) break; // EOF
|
if (len == 0)
|
||||||
|
break; // EOF
|
||||||
|
|
||||||
if (periodicRollingCalendar.shouldRoll)
|
if (periodicRollingCalendar.shouldRoll)
|
||||||
{// rotate at the line boundary
|
{
|
||||||
|
// rotate at the line boundary
|
||||||
int offset = 0;
|
int offset = 0;
|
||||||
bool rolled = false;
|
bool rolled = false;
|
||||||
for (int i = 0; i < len; i++)
|
for (int i = 0; i < len; i++)
|
||||||
{
|
{
|
||||||
if (buf[i] == 0x0A)
|
if (buf[i] == 0x0A)
|
||||||
{// at the line boundary.
|
{
|
||||||
|
// at the line boundary.
|
||||||
// time to rotate.
|
// time to rotate.
|
||||||
w.Write(buf, offset, i + 1);
|
w.Write(buf, offset, i + 1);
|
||||||
w.Close();
|
w.Close();
|
||||||
|
@ -189,24 +201,25 @@ namespace winsw
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!rolled)
|
if (!rolled)
|
||||||
{// we didn't roll - most likely as we didnt find a line boundary, so we should log what we read and roll anyway.
|
{
|
||||||
|
// we didn't roll - most likely as we didnt find a line boundary, so we should log what we read and roll anyway.
|
||||||
w.Write(buf, 0, len);
|
w.Write(buf, 0, len);
|
||||||
w.Close();
|
w.Close();
|
||||||
w = new FileStream(BaseLogFileName + "_" + periodicRollingCalendar.format + ext, FileMode.Create);
|
w = new FileStream(BaseLogFileName + "_" + periodicRollingCalendar.format + ext, FileMode.Create);
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{// typical case. write the whole thing into the current file
|
{
|
||||||
|
// typical case. write the whole thing into the current file
|
||||||
w.Write(buf, 0, len);
|
w.Write(buf, 0, len);
|
||||||
}
|
}
|
||||||
|
|
||||||
w.Flush();
|
w.Flush();
|
||||||
}
|
}
|
||||||
|
|
||||||
data.Close();
|
data.Close();
|
||||||
w.Close();
|
w.Close();
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public class SizeBasedRollingLogAppender : AbstractFileLogAppender
|
public class SizeBasedRollingLogAppender : AbstractFileLogAppender
|
||||||
|
@ -220,9 +233,9 @@ namespace winsw
|
||||||
// ReSharper disable once InconsistentNaming
|
// ReSharper disable once InconsistentNaming
|
||||||
public static int DEFAULT_FILES_TO_KEEP = 8;
|
public static int DEFAULT_FILES_TO_KEEP = 8;
|
||||||
|
|
||||||
public int SizeTheshold { private set; get; }
|
public int SizeTheshold { get; private set; }
|
||||||
|
|
||||||
public int FilesToKeep { private set; get; }
|
public int FilesToKeep { get; private set; }
|
||||||
|
|
||||||
public SizeBasedRollingLogAppender(string logDirectory, string baseName, bool outFileDisabled, bool errFileDisabled, string outFilePattern, string errFilePattern, int sizeThreshold, int filesToKeep)
|
public SizeBasedRollingLogAppender(string logDirectory, string baseName, bool outFileDisabled, bool errFileDisabled, string outFilePattern, string errFilePattern, int sizeThreshold, int filesToKeep)
|
||||||
: base(logDirectory, baseName, outFileDisabled, errFileDisabled, outFilePattern, errFilePattern)
|
: base(logDirectory, baseName, outFileDisabled, errFileDisabled, outFilePattern, errFilePattern)
|
||||||
|
@ -236,8 +249,11 @@ namespace winsw
|
||||||
|
|
||||||
public override void log(Stream outputStream, Stream errorStream)
|
public override void log(Stream outputStream, Stream errorStream)
|
||||||
{
|
{
|
||||||
if (!OutFileDisabled) new Thread(delegate() { CopyStreamWithRotation(outputStream, OutFilePattern); }).Start();
|
if (!OutFileDisabled)
|
||||||
if (!ErrFileDisabled) new Thread(delegate() { CopyStreamWithRotation(errorStream, ErrFilePattern); }).Start();
|
new Thread(() => CopyStreamWithRotation(outputStream, OutFilePattern)).Start();
|
||||||
|
|
||||||
|
if (!ErrFileDisabled)
|
||||||
|
new Thread(() => CopyStreamWithRotation(errorStream, ErrFilePattern)).Start();
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
|
@ -252,9 +268,12 @@ namespace winsw
|
||||||
while (true)
|
while (true)
|
||||||
{
|
{
|
||||||
int len = data.Read(buf, 0, buf.Length);
|
int len = data.Read(buf, 0, buf.Length);
|
||||||
if (len == 0) break; // EOF
|
if (len == 0)
|
||||||
|
break; // EOF
|
||||||
|
|
||||||
if (sz + len < SizeTheshold)
|
if (sz + len < SizeTheshold)
|
||||||
{// typical case. write the whole thing into the current file
|
{
|
||||||
|
// typical case. write the whole thing into the current file
|
||||||
w.Write(buf, 0, len);
|
w.Write(buf, 0, len);
|
||||||
sz += len;
|
sz += len;
|
||||||
}
|
}
|
||||||
|
@ -264,8 +283,11 @@ namespace winsw
|
||||||
int s = 0;
|
int s = 0;
|
||||||
for (int i = 0; i < len; i++)
|
for (int i = 0; i < len; i++)
|
||||||
{
|
{
|
||||||
if (buf[i] != 0x0A) continue;
|
if (buf[i] != 0x0A)
|
||||||
if (sz + i < SizeTheshold) continue;
|
continue;
|
||||||
|
|
||||||
|
if (sz + i < SizeTheshold)
|
||||||
|
continue;
|
||||||
|
|
||||||
// at the line boundary and exceeded the rotation unit.
|
// at the line boundary and exceeded the rotation unit.
|
||||||
// time to rotate.
|
// time to rotate.
|
||||||
|
@ -281,9 +303,11 @@ namespace winsw
|
||||||
string src = BaseLogFileName + "." + (j - 2) + ext;
|
string src = BaseLogFileName + "." + (j - 2) + ext;
|
||||||
if (File.Exists(dst))
|
if (File.Exists(dst))
|
||||||
File.Delete(dst);
|
File.Delete(dst);
|
||||||
|
|
||||||
if (File.Exists(src))
|
if (File.Exists(src))
|
||||||
File.Move(src, dst);
|
File.Move(src, dst);
|
||||||
}
|
}
|
||||||
|
|
||||||
File.Move(BaseLogFileName + ext, BaseLogFileName + ".0" + ext);
|
File.Move(BaseLogFileName + ext, BaseLogFileName + ".0" + ext);
|
||||||
}
|
}
|
||||||
catch (IOException e)
|
catch (IOException e)
|
||||||
|
@ -300,6 +324,7 @@ namespace winsw
|
||||||
|
|
||||||
w.Flush();
|
w.Flush();
|
||||||
}
|
}
|
||||||
|
|
||||||
data.Close();
|
data.Close();
|
||||||
w.Close();
|
w.Close();
|
||||||
}
|
}
|
||||||
|
@ -317,8 +342,12 @@ namespace winsw
|
||||||
|
|
||||||
public override void log(Stream outputStream, Stream errorStream)
|
public override void log(Stream outputStream, Stream errorStream)
|
||||||
{
|
{
|
||||||
if (!OutFileDisabled) CopyFile(OutputLogFileName, OutputLogFileName + ".old");
|
if (!OutFileDisabled)
|
||||||
if (!ErrFileDisabled) CopyFile(ErrorLogFileName, ErrorLogFileName + ".old");
|
CopyFile(OutputLogFileName, OutputLogFileName + ".old");
|
||||||
|
|
||||||
|
if (!ErrFileDisabled)
|
||||||
|
CopyFile(ErrorLogFileName, ErrorLogFileName + ".old");
|
||||||
|
|
||||||
base.log(outputStream, errorStream);
|
base.log(outputStream, errorStream);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -326,11 +355,11 @@ namespace winsw
|
||||||
public class RollingSizeTimeLogAppender : AbstractFileLogAppender
|
public class RollingSizeTimeLogAppender : AbstractFileLogAppender
|
||||||
{
|
{
|
||||||
public static int BYTES_PER_KB = 1024;
|
public static int BYTES_PER_KB = 1024;
|
||||||
public int SizeTheshold { private set; get; }
|
public int SizeTheshold { get; private set; }
|
||||||
public string FilePattern { private set; get; }
|
public string FilePattern { get; private set; }
|
||||||
public TimeSpan? AutoRollAtTime { private set; get; }
|
public TimeSpan? AutoRollAtTime { get; private set; }
|
||||||
public int? ZipOlderThanNumDays { private set; get; }
|
public int? ZipOlderThanNumDays { get; private set; }
|
||||||
public string ZipDateFormat { private set; get; }
|
public string ZipDateFormat { get; private set; }
|
||||||
|
|
||||||
public RollingSizeTimeLogAppender(string logDirectory, string baseName, bool outFileDisabled, bool errFileDisabled, string outFilePattern, string errFilePattern, int sizeThreshold, string filePattern, TimeSpan? autoRollAtTime, int? zipolderthannumdays, string zipdateformat)
|
public RollingSizeTimeLogAppender(string logDirectory, string baseName, bool outFileDisabled, bool errFileDisabled, string outFilePattern, string errFilePattern, int sizeThreshold, string filePattern, TimeSpan? autoRollAtTime, int? zipolderthannumdays, string zipdateformat)
|
||||||
: base(logDirectory, baseName, outFileDisabled, errFileDisabled, outFilePattern, errFilePattern)
|
: base(logDirectory, baseName, outFileDisabled, errFileDisabled, outFilePattern, errFilePattern)
|
||||||
|
@ -344,8 +373,11 @@ namespace winsw
|
||||||
|
|
||||||
public override void log(Stream outputStream, Stream errorStream)
|
public override void log(Stream outputStream, Stream errorStream)
|
||||||
{
|
{
|
||||||
if (!OutFileDisabled) new Thread(delegate () { CopyStreamWithRotation(outputStream, OutFilePattern); }).Start();
|
if (!OutFileDisabled)
|
||||||
if (!ErrFileDisabled) new Thread(delegate () { CopyStreamWithRotation(errorStream, ErrFilePattern); }).Start();
|
new Thread(() => CopyStreamWithRotation(outputStream, OutFilePattern)).Start();
|
||||||
|
|
||||||
|
if (!ErrFileDisabled)
|
||||||
|
new Thread(() => CopyStreamWithRotation(errorStream, ErrFilePattern)).Start();
|
||||||
}
|
}
|
||||||
|
|
||||||
private void CopyStreamWithRotation(Stream data, string ext)
|
private void CopyStreamWithRotation(Stream data, string ext)
|
||||||
|
@ -402,10 +434,13 @@ namespace winsw
|
||||||
};
|
};
|
||||||
timer.Start();
|
timer.Start();
|
||||||
}
|
}
|
||||||
|
|
||||||
while (true)
|
while (true)
|
||||||
{
|
{
|
||||||
var len = data.Read(buf, 0, buf.Length);
|
var len = data.Read(buf, 0, buf.Length);
|
||||||
if (len == 0) break; // EOF
|
if (len == 0)
|
||||||
|
break; // EOF
|
||||||
|
|
||||||
lock (fileLock)
|
lock (fileLock)
|
||||||
{
|
{
|
||||||
if (sz + len < SizeTheshold)
|
if (sz + len < SizeTheshold)
|
||||||
|
@ -422,8 +457,11 @@ namespace winsw
|
||||||
int s = 0;
|
int s = 0;
|
||||||
for (int i = 0; i < len; i++)
|
for (int i = 0; i < len; i++)
|
||||||
{
|
{
|
||||||
if (buf[i] != 0x0A) continue;
|
if (buf[i] != 0x0A)
|
||||||
if (sz + i < SizeTheshold) continue;
|
continue;
|
||||||
|
|
||||||
|
if (sz + i < SizeTheshold)
|
||||||
|
continue;
|
||||||
|
|
||||||
// at the line boundary and exceeded the rotation unit.
|
// at the line boundary and exceeded the rotation unit.
|
||||||
// time to rotate.
|
// time to rotate.
|
||||||
|
@ -450,16 +488,19 @@ namespace winsw
|
||||||
EventLogger.LogEvent(string.Format("Failed to roll size time log: {0}", e.Message));
|
EventLogger.LogEvent(string.Format("Failed to roll size time log: {0}", e.Message));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
w.Flush();
|
w.Flush();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
data.Close();
|
data.Close();
|
||||||
w.Close();
|
w.Close();
|
||||||
}
|
}
|
||||||
|
|
||||||
private void ZipFiles(string path, string fileExt, string baseZipfilename)
|
private void ZipFiles(string path, string fileExt, string baseZipfilename)
|
||||||
{
|
{
|
||||||
if (ZipOlderThanNumDays == null || !(ZipOlderThanNumDays > 0)) return;
|
if (ZipOlderThanNumDays == null || !(ZipOlderThanNumDays > 0))
|
||||||
|
return;
|
||||||
|
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
|
@ -467,7 +508,8 @@ namespace winsw
|
||||||
foreach (var file in files)
|
foreach (var file in files)
|
||||||
{
|
{
|
||||||
var fi = new FileInfo(file);
|
var fi = new FileInfo(file);
|
||||||
if (fi.LastWriteTimeUtc >= DateTime.UtcNow.AddDays(-ZipOlderThanNumDays.Value)) continue;
|
if (fi.LastWriteTimeUtc >= DateTime.UtcNow.AddDays(-ZipOlderThanNumDays.Value))
|
||||||
|
continue;
|
||||||
|
|
||||||
// lets archive this bugger
|
// lets archive this bugger
|
||||||
ZipTheFile(file, path, fi.LastWriteTimeUtc.ToString(ZipDateFormat), baseZipfilename);
|
ZipTheFile(file, path, fi.LastWriteTimeUtc.ToString(ZipDateFormat), baseZipfilename);
|
||||||
|
@ -487,7 +529,6 @@ namespace winsw
|
||||||
bool commited = false;
|
bool commited = false;
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
|
|
||||||
if (File.Exists(zipfilename))
|
if (File.Exists(zipfilename))
|
||||||
{
|
{
|
||||||
zipFile = new ZipFile(zipfilename);
|
zipFile = new ZipFile(zipfilename);
|
||||||
|
@ -539,11 +580,11 @@ namespace winsw
|
||||||
{
|
{
|
||||||
var nowTime = DateTime.Now;
|
var nowTime = DateTime.Now;
|
||||||
var scheduledTime = new DateTime(nowTime.Year, nowTime.Month, nowTime.Day, AutoRollAtTime.Value.Hours,
|
var scheduledTime = new DateTime(nowTime.Year, nowTime.Month, nowTime.Day, AutoRollAtTime.Value.Hours,
|
||||||
AutoRollAtTime.Value.Minutes, AutoRollAtTime.Value.Seconds, 0); //Specify your time HH,MM,SS
|
AutoRollAtTime.Value.Minutes, AutoRollAtTime.Value.Seconds, 0); // Specify your time HH,MM,SS
|
||||||
if (nowTime > scheduledTime)
|
if (nowTime > scheduledTime)
|
||||||
scheduledTime = scheduledTime.AddDays(1);
|
scheduledTime = scheduledTime.AddDays(1);
|
||||||
|
|
||||||
double tickTime = (double) (scheduledTime - DateTime.Now).TotalMilliseconds;
|
double tickTime = (scheduledTime - DateTime.Now).TotalMilliseconds;
|
||||||
return tickTime;
|
return tickTime;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -564,24 +605,29 @@ namespace winsw
|
||||||
var filenameOnly = Path.GetFileNameWithoutExtension(f);
|
var filenameOnly = Path.GetFileNameWithoutExtension(f);
|
||||||
var hashIndex = filenameOnly.IndexOf('#');
|
var hashIndex = filenameOnly.IndexOf('#');
|
||||||
var lastNumberAsString = filenameOnly.Substring(hashIndex + 1, 4);
|
var lastNumberAsString = filenameOnly.Substring(hashIndex + 1, 4);
|
||||||
//var lastNumberAsString = filenameOnly.Substring(filenameOnly.Length - 4, 4);
|
// var lastNumberAsString = filenameOnly.Substring(filenameOnly.Length - 4, 4);
|
||||||
int lastNumber = 0;
|
if (int.TryParse(lastNumberAsString, out int lastNumber))
|
||||||
if (int.TryParse(lastNumberAsString, out lastNumber))
|
|
||||||
{
|
{
|
||||||
if (lastNumber > nextFileNumber)
|
if (lastNumber > nextFileNumber)
|
||||||
nextFileNumber = lastNumber;
|
nextFileNumber = lastNumber;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
throw new IOException(string.Format("File {0} does not follow the pattern provided",f));
|
{
|
||||||
|
throw new IOException(string.Format("File {0} does not follow the pattern provided", f));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
catch (Exception e)
|
catch (Exception e)
|
||||||
{
|
{
|
||||||
throw new IOException(string.Format("Failed to process file {0} due to error {1}",f, e.Message), e);
|
throw new IOException(string.Format("Failed to process file {0} due to error {1}", f, e.Message), e);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (nextFileNumber == 0) throw new IOException("Cannot roll the file because matching pattern not found");
|
|
||||||
|
if (nextFileNumber == 0)
|
||||||
|
throw new IOException("Cannot roll the file because matching pattern not found");
|
||||||
|
|
||||||
nextFileNumber++;
|
nextFileNumber++;
|
||||||
}
|
}
|
||||||
|
|
||||||
return nextFileNumber;
|
return nextFileNumber;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,7 +1,4 @@
|
||||||
using System;
|
using System.Diagnostics;
|
||||||
using System.Collections.Generic;
|
|
||||||
using System.Diagnostics;
|
|
||||||
using System.Text;
|
|
||||||
|
|
||||||
namespace winsw.Logging
|
namespace winsw.Logging
|
||||||
{
|
{
|
||||||
|
|
|
@ -1,9 +1,6 @@
|
||||||
using log4net.Appender;
|
using System.Diagnostics;
|
||||||
|
using log4net.Appender;
|
||||||
using log4net.Core;
|
using log4net.Core;
|
||||||
using System;
|
|
||||||
using System.Collections.Generic;
|
|
||||||
using System.Diagnostics;
|
|
||||||
using System.Text;
|
|
||||||
|
|
||||||
namespace winsw.Logging
|
namespace winsw.Logging
|
||||||
{
|
{
|
||||||
|
@ -31,6 +28,7 @@ namespace winsw.Logging
|
||||||
{
|
{
|
||||||
return EventLogEntryType.Error;
|
return EventLogEntryType.Error;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (level.Value >= Level.Warn.Value)
|
if (level.Value >= Level.Warn.Value)
|
||||||
{
|
{
|
||||||
return EventLogEntryType.Warning;
|
return EventLogEntryType.Warning;
|
||||||
|
|
|
@ -28,6 +28,7 @@ namespace winsw.Native
|
||||||
{
|
{
|
||||||
throw new Exception(String.Format("Error opening service for modifying. Error returned was: 0x{0:X}", Marshal.GetLastWin32Error()));
|
throw new Exception(String.Format("Error opening service for modifying. Error returned was: 0x{0:X}", Marshal.GetLastWin32Error()));
|
||||||
}
|
}
|
||||||
|
|
||||||
return new Service(svcHandle);
|
return new Service(svcHandle);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -52,9 +53,9 @@ namespace winsw.Native
|
||||||
{
|
{
|
||||||
SERVICE_FAILURE_ACTIONS sfa = new SERVICE_FAILURE_ACTIONS
|
SERVICE_FAILURE_ACTIONS sfa = new SERVICE_FAILURE_ACTIONS
|
||||||
{
|
{
|
||||||
dwResetPeriod = (int) failureResetPeriod.TotalSeconds,
|
dwResetPeriod = (int)failureResetPeriod.TotalSeconds,
|
||||||
lpRebootMsg = "",
|
lpRebootMsg = string.Empty,
|
||||||
lpCommand = ""
|
lpCommand = string.Empty
|
||||||
};
|
};
|
||||||
// delete message
|
// delete message
|
||||||
// delete the command to run
|
// delete the command to run
|
||||||
|
@ -101,7 +102,7 @@ namespace winsw.Native
|
||||||
|
|
||||||
public void Dispose()
|
public void Dispose()
|
||||||
{
|
{
|
||||||
if (Handle!=IntPtr.Zero)
|
if (Handle != IntPtr.Zero)
|
||||||
Advapi32.CloseServiceHandle(Handle);
|
Advapi32.CloseServiceHandle(Handle);
|
||||||
Handle = IntPtr.Zero;
|
Handle = IntPtr.Zero;
|
||||||
}
|
}
|
||||||
|
@ -111,14 +112,14 @@ namespace winsw.Native
|
||||||
{
|
{
|
||||||
public static void AddLogonAsAServiceRight(string username)
|
public static void AddLogonAsAServiceRight(string username)
|
||||||
{
|
{
|
||||||
//Needs to be at least XP or 2003 server
|
// Needs to be at least XP or 2003 server
|
||||||
//https://msdn.microsoft.com/en-us/library/windows/desktop/ms724832%28v=vs.85%29.aspx
|
// https://msdn.microsoft.com/en-us/library/windows/desktop/ms724832%28v=vs.85%29.aspx
|
||||||
OperatingSystem osInfo = Environment.OSVersion;
|
OperatingSystem osInfo = Environment.OSVersion;
|
||||||
|
|
||||||
if (osInfo.Version.Major >= 5 && osInfo.Version.Minor >= 1)
|
if (osInfo.Version.Major >= 5 && osInfo.Version.Minor >= 1)
|
||||||
{
|
{
|
||||||
var newuser = GetLocalAccountIfLocalAccount(username);
|
var newuser = GetLocalAccountIfLocalAccount(username);
|
||||||
//Trace.WriteLine("Username for Logon as A Service: " + newuser);
|
// Trace.WriteLine("Username for Logon as A Service: " + newuser);
|
||||||
long rightexitcode = SetRight(newuser, PrivlegeRights.SeServiceLogonRight.ToString());
|
long rightexitcode = SetRight(newuser, PrivlegeRights.SeServiceLogonRight.ToString());
|
||||||
if (rightexitcode != 0)
|
if (rightexitcode != 0)
|
||||||
{
|
{
|
||||||
|
@ -155,6 +156,7 @@ namespace winsw.Native
|
||||||
{
|
{
|
||||||
return GetLogin(username);
|
return GetLogin(username);
|
||||||
}
|
}
|
||||||
|
|
||||||
return username;
|
return username;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -164,32 +166,32 @@ namespace winsw.Native
|
||||||
/// <returns>The windows error code returned by LsaAddAccountRights</returns>
|
/// <returns>The windows error code returned by LsaAddAccountRights</returns>
|
||||||
private static long SetRight(String accountName, String privilegeName)
|
private static long SetRight(String accountName, String privilegeName)
|
||||||
{
|
{
|
||||||
long winErrorCode = 0; //contains the last error
|
long winErrorCode; // contains the last error
|
||||||
|
|
||||||
//pointer an size for the SID
|
// pointer an size for the SID
|
||||||
IntPtr sid = IntPtr.Zero;
|
IntPtr sid = IntPtr.Zero;
|
||||||
int sidSize = 0;
|
int sidSize = 0;
|
||||||
//StringBuilder and size for the domain name
|
// StringBuilder and size for the domain name
|
||||||
StringBuilder domainName = new StringBuilder();
|
StringBuilder domainName = new StringBuilder();
|
||||||
int nameSize = 0;
|
int nameSize = 0;
|
||||||
//account-type variable for lookup
|
// account-type variable for lookup
|
||||||
int accountType = 0;
|
int accountType = 0;
|
||||||
|
|
||||||
//get required buffer size
|
// get required buffer size
|
||||||
Advapi32.LookupAccountName(String.Empty, accountName, sid, ref sidSize, domainName, ref nameSize, ref accountType);
|
Advapi32.LookupAccountName(String.Empty, accountName, sid, ref sidSize, domainName, ref nameSize, ref accountType);
|
||||||
|
|
||||||
//allocate buffers
|
// allocate buffers
|
||||||
domainName = new StringBuilder(nameSize);
|
domainName = new StringBuilder(nameSize);
|
||||||
sid = Marshal.AllocHGlobal(sidSize);
|
sid = Marshal.AllocHGlobal(sidSize);
|
||||||
|
|
||||||
//lookup the SID for the account
|
// lookup the SID for the account
|
||||||
bool result = Advapi32.LookupAccountName(String.Empty, accountName, sid, ref sidSize, domainName, ref nameSize,
|
bool result = Advapi32.LookupAccountName(String.Empty, accountName, sid, ref sidSize, domainName, ref nameSize,
|
||||||
ref accountType);
|
ref accountType);
|
||||||
|
|
||||||
//say what you're doing
|
// say what you're doing
|
||||||
//Console.WriteLine("LookupAccountName result = " + result);
|
// Console.WriteLine("LookupAccountName result = " + result);
|
||||||
//Console.WriteLine("IsValidSid: " + Advapi32.IsValidSid(sid));
|
// Console.WriteLine("IsValidSid: " + Advapi32.IsValidSid(sid));
|
||||||
//Console.WriteLine("LookupAccountName domainName: " + domainName.ToString());
|
// Console.WriteLine("LookupAccountName domainName: " + domainName.ToString());
|
||||||
|
|
||||||
if (!result)
|
if (!result)
|
||||||
{
|
{
|
||||||
|
@ -198,10 +200,9 @@ namespace winsw.Native
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
// initialize an empty unicode-string
|
||||||
//initialize an empty unicode-string
|
LSA_UNICODE_STRING systemName = default;
|
||||||
LSA_UNICODE_STRING systemName = new LSA_UNICODE_STRING();
|
// combine all policies
|
||||||
//combine all policies
|
|
||||||
const int access = (int)(
|
const int access = (int)(
|
||||||
LSA_AccessPolicy.POLICY_AUDIT_LOG_ADMIN |
|
LSA_AccessPolicy.POLICY_AUDIT_LOG_ADMIN |
|
||||||
LSA_AccessPolicy.POLICY_CREATE_ACCOUNT |
|
LSA_AccessPolicy.POLICY_CREATE_ACCOUNT |
|
||||||
|
@ -217,10 +218,9 @@ namespace winsw.Native
|
||||||
LSA_AccessPolicy.POLICY_VIEW_AUDIT_INFORMATION |
|
LSA_AccessPolicy.POLICY_VIEW_AUDIT_INFORMATION |
|
||||||
LSA_AccessPolicy.POLICY_VIEW_LOCAL_INFORMATION
|
LSA_AccessPolicy.POLICY_VIEW_LOCAL_INFORMATION
|
||||||
);
|
);
|
||||||
//initialize a pointer for the policy handle
|
// initialize a pointer for the policy handle
|
||||||
IntPtr policyHandle = IntPtr.Zero;
|
|
||||||
|
|
||||||
//these attributes are not used, but LsaOpenPolicy wants them to exists
|
// these attributes are not used, but LsaOpenPolicy wants them to exists
|
||||||
LSA_OBJECT_ATTRIBUTES objectAttributes = new LSA_OBJECT_ATTRIBUTES
|
LSA_OBJECT_ATTRIBUTES objectAttributes = new LSA_OBJECT_ATTRIBUTES
|
||||||
{
|
{
|
||||||
Length = 0,
|
Length = 0,
|
||||||
|
@ -230,8 +230,8 @@ namespace winsw.Native
|
||||||
SecurityQualityOfService = IntPtr.Zero
|
SecurityQualityOfService = IntPtr.Zero
|
||||||
};
|
};
|
||||||
|
|
||||||
//get a policy handle
|
// get a policy handle
|
||||||
uint resultPolicy = Advapi32.LsaOpenPolicy(ref systemName, ref objectAttributes, access, out policyHandle);
|
uint resultPolicy = Advapi32.LsaOpenPolicy(ref systemName, ref objectAttributes, access, out IntPtr policyHandle);
|
||||||
winErrorCode = Advapi32.LsaNtStatusToWinError(resultPolicy);
|
winErrorCode = Advapi32.LsaNtStatusToWinError(resultPolicy);
|
||||||
|
|
||||||
if (winErrorCode != 0)
|
if (winErrorCode != 0)
|
||||||
|
@ -240,17 +240,17 @@ namespace winsw.Native
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
//Now that we have the SID an the policy,
|
// Now that we have the SID an the policy,
|
||||||
//we can add rights to the account.
|
// we can add rights to the account.
|
||||||
|
|
||||||
//initialize an unicode-string for the privilege name
|
// initialize an unicode-string for the privilege name
|
||||||
LSA_UNICODE_STRING[] userRights = new LSA_UNICODE_STRING[1];
|
LSA_UNICODE_STRING[] userRights = new LSA_UNICODE_STRING[1];
|
||||||
userRights[0] = new LSA_UNICODE_STRING();
|
userRights[0] = default;
|
||||||
userRights[0].Buffer = Marshal.StringToHGlobalUni(privilegeName);
|
userRights[0].Buffer = Marshal.StringToHGlobalUni(privilegeName);
|
||||||
userRights[0].Length = (UInt16)(privilegeName.Length * UnicodeEncoding.CharSize);
|
userRights[0].Length = (UInt16)(privilegeName.Length * UnicodeEncoding.CharSize);
|
||||||
userRights[0].MaximumLength = (UInt16)((privilegeName.Length + 1) * UnicodeEncoding.CharSize);
|
userRights[0].MaximumLength = (UInt16)((privilegeName.Length + 1) * UnicodeEncoding.CharSize);
|
||||||
|
|
||||||
//add the right to the account
|
// add the right to the account
|
||||||
uint res = Advapi32.LsaAddAccountRights(policyHandle, sid, userRights, 1);
|
uint res = Advapi32.LsaAddAccountRights(policyHandle, sid, userRights, 1);
|
||||||
winErrorCode = Advapi32.LsaNtStatusToWinError(res);
|
winErrorCode = Advapi32.LsaNtStatusToWinError(res);
|
||||||
if (winErrorCode != 0)
|
if (winErrorCode != 0)
|
||||||
|
@ -260,6 +260,7 @@ namespace winsw.Native
|
||||||
|
|
||||||
Advapi32.LsaClose(policyHandle);
|
Advapi32.LsaClose(policyHandle);
|
||||||
}
|
}
|
||||||
|
|
||||||
Advapi32.FreeSid(sid);
|
Advapi32.FreeSid(sid);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -320,22 +321,21 @@ namespace winsw.Native
|
||||||
|
|
||||||
[DllImport("advapi32.dll", SetLastError = false)]
|
[DllImport("advapi32.dll", SetLastError = false)]
|
||||||
internal static extern uint LsaNtStatusToWinError(uint status);
|
internal static extern uint LsaNtStatusToWinError(uint status);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
//http://msdn.microsoft.com/en-us/library/windows/desktop/bb545671(v=vs.85).aspx
|
// http://msdn.microsoft.com/en-us/library/windows/desktop/bb545671(v=vs.85).aspx
|
||||||
internal enum PrivlegeRights
|
internal enum PrivlegeRights
|
||||||
{
|
{
|
||||||
SeServiceLogonRight, //Required for an account to log on using the service logon type.
|
SeServiceLogonRight, // Required for an account to log on using the service logon type.
|
||||||
SeRemoteInteractiveLogonRight, //Required for an account to log on remotely using the interactive logon type.
|
SeRemoteInteractiveLogonRight, // Required for an account to log on remotely using the interactive logon type.
|
||||||
SeNetworkLogonRight, //Required for an account to log on using the network logon type.
|
SeNetworkLogonRight, // Required for an account to log on using the network logon type.
|
||||||
SeInteractiveLogonRight, //Required for an account to log on using the interactive logon type.
|
SeInteractiveLogonRight, // Required for an account to log on using the interactive logon type.
|
||||||
SeDenyServiceLogonRight, //Explicitly denies an account the right to log on using the service logon type.
|
SeDenyServiceLogonRight, // Explicitly denies an account the right to log on using the service logon type.
|
||||||
SeDenyRemoteInteractiveLogonRight, //Explicitly denies an account the right to log on remotely using the interactive logon type.
|
SeDenyRemoteInteractiveLogonRight, // Explicitly denies an account the right to log on remotely using the interactive logon type.
|
||||||
SeDenyNetworkLogonRight, //Explicitly denies an account the right to log on using the network logon type.
|
SeDenyNetworkLogonRight, // Explicitly denies an account the right to log on using the network logon type.
|
||||||
SeDenyInteractiveLogonRight, //Explicitly denies an account the right to log on using the interactive logon type.
|
SeDenyInteractiveLogonRight, // Explicitly denies an account the right to log on using the interactive logon type.
|
||||||
SeDenyBatchLogonRight, //Explicitly denies an account the right to log on using the batch logon type.
|
SeDenyBatchLogonRight, // Explicitly denies an account the right to log on using the batch logon type.
|
||||||
SeBatchLogonRight //Required for an account to log on using the batch logon type.
|
SeBatchLogonRight // Required for an account to log on using the batch logon type.
|
||||||
}
|
}
|
||||||
|
|
||||||
[StructLayout(LayoutKind.Sequential)]
|
[StructLayout(LayoutKind.Sequential)]
|
||||||
|
@ -452,7 +452,7 @@ namespace winsw.Native
|
||||||
SERVICE_PAUSE_CONTINUE = 0x00040,
|
SERVICE_PAUSE_CONTINUE = 0x00040,
|
||||||
SERVICE_INTERROGATE = 0x00080,
|
SERVICE_INTERROGATE = 0x00080,
|
||||||
SERVICE_USER_DEFINED_CONTROL = 0x00100,
|
SERVICE_USER_DEFINED_CONTROL = 0x00100,
|
||||||
SERVICE_ALL_ACCESS = (STANDARD_RIGHTS_REQUIRED |
|
SERVICE_ALL_ACCESS = STANDARD_RIGHTS_REQUIRED |
|
||||||
SERVICE_QUERY_CONFIG |
|
SERVICE_QUERY_CONFIG |
|
||||||
SERVICE_CHANGE_CONFIG |
|
SERVICE_CHANGE_CONFIG |
|
||||||
SERVICE_QUERY_STATUS |
|
SERVICE_QUERY_STATUS |
|
||||||
|
@ -461,7 +461,7 @@ namespace winsw.Native
|
||||||
SERVICE_STOP |
|
SERVICE_STOP |
|
||||||
SERVICE_PAUSE_CONTINUE |
|
SERVICE_PAUSE_CONTINUE |
|
||||||
SERVICE_INTERROGATE |
|
SERVICE_INTERROGATE |
|
||||||
SERVICE_USER_DEFINED_CONTROL)
|
SERVICE_USER_DEFINED_CONTROL
|
||||||
}
|
}
|
||||||
|
|
||||||
[Flags]
|
[Flags]
|
||||||
|
@ -537,7 +537,6 @@ namespace winsw.Native
|
||||||
SERVICE_PAUSED = 0x00000007,
|
SERVICE_PAUSED = 0x00000007,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
// http://msdn.microsoft.com/en-us/library/windows/desktop/ms685126(v=vs.85).aspx
|
// http://msdn.microsoft.com/en-us/library/windows/desktop/ms685126(v=vs.85).aspx
|
||||||
[StructLayout(LayoutKind.Sequential)]
|
[StructLayout(LayoutKind.Sequential)]
|
||||||
public struct SC_ACTION
|
public struct SC_ACTION
|
||||||
|
@ -577,7 +576,7 @@ namespace winsw.Native
|
||||||
}
|
}
|
||||||
|
|
||||||
// http://msdn.microsoft.com/en-us/library/windows/desktop/ms685939(v=vs.85).aspx
|
// http://msdn.microsoft.com/en-us/library/windows/desktop/ms685939(v=vs.85).aspx
|
||||||
[StructLayout(LayoutKind.Sequential,CharSet=CharSet.Unicode)]
|
[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Unicode)]
|
||||||
public struct SERVICE_FAILURE_ACTIONS
|
public struct SERVICE_FAILURE_ACTIONS
|
||||||
{
|
{
|
||||||
/// <summary>
|
/// <summary>
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
using Microsoft.Win32.SafeHandles;
|
using System;
|
||||||
using System;
|
|
||||||
using System.Runtime.InteropServices;
|
using System.Runtime.InteropServices;
|
||||||
|
using Microsoft.Win32.SafeHandles;
|
||||||
|
|
||||||
namespace winsw.Native
|
namespace winsw.Native
|
||||||
{
|
{
|
||||||
|
|
|
@ -29,10 +29,16 @@ namespace winsw
|
||||||
|
|
||||||
public enum PeriodicityType
|
public enum PeriodicityType
|
||||||
{
|
{
|
||||||
ERRONEOUS, TOP_OF_MILLISECOND, TOP_OF_SECOND, TOP_OF_MINUTE, TOP_OF_HOUR, TOP_OF_DAY
|
ERRONEOUS,
|
||||||
|
TOP_OF_MILLISECOND,
|
||||||
|
TOP_OF_SECOND,
|
||||||
|
TOP_OF_MINUTE,
|
||||||
|
TOP_OF_HOUR,
|
||||||
|
TOP_OF_DAY
|
||||||
}
|
}
|
||||||
|
|
||||||
private static readonly PeriodicityType[] VALID_ORDERED_LIST = {
|
private static readonly PeriodicityType[] VALID_ORDERED_LIST =
|
||||||
|
{
|
||||||
PeriodicityType.TOP_OF_MILLISECOND, PeriodicityType.TOP_OF_SECOND, PeriodicityType.TOP_OF_MINUTE, PeriodicityType.TOP_OF_HOUR, PeriodicityType.TOP_OF_DAY
|
PeriodicityType.TOP_OF_MILLISECOND, PeriodicityType.TOP_OF_SECOND, PeriodicityType.TOP_OF_MINUTE, PeriodicityType.TOP_OF_HOUR, PeriodicityType.TOP_OF_DAY
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -54,6 +60,7 @@ namespace winsw
|
||||||
return i;
|
return i;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return PeriodicityType.ERRONEOUS;
|
return PeriodicityType.ERRONEOUS;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -100,17 +107,11 @@ namespace winsw
|
||||||
_nextRoll = nextTriggeringTime(now, _period);
|
_nextRoll = nextTriggeringTime(now, _period);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public string format
|
public string format => _currentRoll.ToString(_format);
|
||||||
{
|
|
||||||
get
|
|
||||||
{
|
|
||||||
return _currentRoll.ToString(_format);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -3,7 +3,6 @@ using System.Collections;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Diagnostics;
|
using System.Diagnostics;
|
||||||
using System.IO;
|
using System.IO;
|
||||||
using System.Reflection;
|
|
||||||
using System.Xml;
|
using System.Xml;
|
||||||
using winsw.Configuration;
|
using winsw.Configuration;
|
||||||
using winsw.Native;
|
using winsw.Native;
|
||||||
|
@ -20,8 +19,7 @@ namespace winsw
|
||||||
// ReSharper disable once InconsistentNaming
|
// ReSharper disable once InconsistentNaming
|
||||||
protected readonly XmlDocument dom = new XmlDocument();
|
protected readonly XmlDocument dom = new XmlDocument();
|
||||||
|
|
||||||
private static readonly DefaultWinSWSettings defaults = new DefaultWinSWSettings();
|
public static DefaultWinSWSettings Defaults { get; } = new DefaultWinSWSettings();
|
||||||
public static DefaultWinSWSettings Defaults { get { return defaults; } }
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Where did we find the configuration file?
|
/// Where did we find the configuration file?
|
||||||
|
@ -37,23 +35,19 @@ namespace winsw
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public string BaseName { get; set; }
|
public string BaseName { get; set; }
|
||||||
|
|
||||||
public virtual string ExecutablePath
|
|
||||||
{
|
|
||||||
get
|
|
||||||
{
|
|
||||||
// Currently there is no opportunity to alter the executable path
|
// Currently there is no opportunity to alter the executable path
|
||||||
return Defaults.ExecutablePath;
|
public virtual string ExecutablePath => Defaults.ExecutablePath;
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public ServiceDescriptor()
|
public ServiceDescriptor()
|
||||||
{
|
{
|
||||||
// find co-located configuration xml. We search up to the ancestor directories to simplify debugging,
|
// find co-located configuration xml. We search up to the ancestor directories to simplify debugging,
|
||||||
// as well as trimming off ".vshost" suffix (which is used during debugging)
|
// as well as trimming off ".vshost" suffix (which is used during debugging)
|
||||||
//Get the first parent to go into the recursive loop
|
// Get the first parent to go into the recursive loop
|
||||||
string p = ExecutablePath;
|
string p = ExecutablePath;
|
||||||
string baseName = Path.GetFileNameWithoutExtension(p);
|
string baseName = Path.GetFileNameWithoutExtension(p);
|
||||||
if (baseName.EndsWith(".vshost")) baseName = baseName.Substring(0, baseName.Length - 7);
|
if (baseName.EndsWith(".vshost"))
|
||||||
|
baseName = baseName.Substring(0, baseName.Length - 7);
|
||||||
|
|
||||||
DirectoryInfo d = new DirectoryInfo(Path.GetDirectoryName(p));
|
DirectoryInfo d = new DirectoryInfo(Path.GetDirectoryName(p));
|
||||||
while (true)
|
while (true)
|
||||||
{
|
{
|
||||||
|
@ -61,7 +55,7 @@ namespace winsw
|
||||||
break;
|
break;
|
||||||
|
|
||||||
if (d.Parent == null)
|
if (d.Parent == null)
|
||||||
throw new FileNotFoundException("Unable to locate "+baseName+".xml file within executable directory or any parents");
|
throw new FileNotFoundException("Unable to locate " + baseName + ".xml file within executable directory or any parents");
|
||||||
|
|
||||||
d = d.Parent;
|
d = d.Parent;
|
||||||
}
|
}
|
||||||
|
@ -73,11 +67,13 @@ namespace winsw
|
||||||
|
|
||||||
// register the base directory as environment variable so that future expansions can refer to this.
|
// register the base directory as environment variable so that future expansions can refer to this.
|
||||||
Environment.SetEnvironmentVariable("BASE", d.FullName);
|
Environment.SetEnvironmentVariable("BASE", d.FullName);
|
||||||
|
|
||||||
// ditto for ID
|
// ditto for ID
|
||||||
Environment.SetEnvironmentVariable("SERVICE_ID", Id);
|
Environment.SetEnvironmentVariable("SERVICE_ID", Id);
|
||||||
|
|
||||||
// New name
|
// New name
|
||||||
Environment.SetEnvironmentVariable(WinSWSystem.ENVVAR_NAME_EXECUTABLE_PATH, ExecutablePath);
|
Environment.SetEnvironmentVariable(WinSWSystem.ENVVAR_NAME_EXECUTABLE_PATH, ExecutablePath);
|
||||||
|
|
||||||
// Also inject system environment variables
|
// Also inject system environment variables
|
||||||
Environment.SetEnvironmentVariable(WinSWSystem.ENVVAR_NAME_SERVICE_ID, Id);
|
Environment.SetEnvironmentVariable(WinSWSystem.ENVVAR_NAME_SERVICE_ID, Id);
|
||||||
}
|
}
|
||||||
|
@ -106,7 +102,9 @@ namespace winsw
|
||||||
private string SingleElement(string tagName, bool optional)
|
private string SingleElement(string tagName, bool optional)
|
||||||
{
|
{
|
||||||
var n = dom.SelectSingleNode("//" + tagName);
|
var n = dom.SelectSingleNode("//" + tagName);
|
||||||
if (n == null && !optional) throw new InvalidDataException("<" + tagName + "> is missing in configuration XML");
|
if (n == null && !optional)
|
||||||
|
throw new InvalidDataException("<" + tagName + "> is missing in configuration XML");
|
||||||
|
|
||||||
return n == null ? null : Environment.ExpandEnvironmentVariables(n.InnerText);
|
return n == null ? null : Environment.ExpandEnvironmentVariables(n.InnerText);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -147,51 +145,36 @@ namespace winsw
|
||||||
return TimeSpan.FromMilliseconds(int.Parse(v.Substring(0, v.Length - s.Key.Length).Trim()) * s.Value);
|
return TimeSpan.FromMilliseconds(int.Parse(v.Substring(0, v.Length - s.Key.Length).Trim()) * s.Value);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return TimeSpan.FromMilliseconds(int.Parse(v));
|
return TimeSpan.FromMilliseconds(int.Parse(v));
|
||||||
}
|
}
|
||||||
|
|
||||||
private static readonly Dictionary<string,long> Suffix = new Dictionary<string,long> {
|
private static readonly Dictionary<string, long> Suffix = new Dictionary<string, long>
|
||||||
|
{
|
||||||
{ "ms", 1 },
|
{ "ms", 1 },
|
||||||
{ "sec", 1000L },
|
{ "sec", 1000L },
|
||||||
{ "secs", 1000L },
|
{ "secs", 1000L },
|
||||||
{ "min", 1000L*60L },
|
{ "min", 1000L * 60L },
|
||||||
{ "mins", 1000L*60L },
|
{ "mins", 1000L * 60L },
|
||||||
{ "hr", 1000L*60L*60L },
|
{ "hr", 1000L * 60L * 60L },
|
||||||
{ "hrs", 1000L*60L*60L },
|
{ "hrs", 1000L * 60L * 60L },
|
||||||
{ "hour", 1000L*60L*60L },
|
{ "hour", 1000L * 60L * 60L },
|
||||||
{ "hours", 1000L*60L*60L },
|
{ "hours", 1000L * 60L * 60L },
|
||||||
{ "day", 1000L*60L*60L*24L },
|
{ "day", 1000L * 60L * 60L * 24L },
|
||||||
{ "days", 1000L*60L*60L*24L }
|
{ "days", 1000L * 60L * 60L * 24L }
|
||||||
};
|
};
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Path to the executable.
|
/// Path to the executable.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public string Executable
|
public string Executable => SingleElement("executable");
|
||||||
{
|
|
||||||
get
|
|
||||||
{
|
|
||||||
return SingleElement("executable");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public bool HideWindow
|
public bool HideWindow => SingleBoolElement("hidewindow", Defaults.HideWindow);
|
||||||
{
|
|
||||||
get {
|
|
||||||
return SingleBoolElement("hidewindow", Defaults.HideWindow);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Optionally specify a different Path to an executable to shutdown the service.
|
/// Optionally specify a different Path to an executable to shutdown the service.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public string StopExecutable
|
public string StopExecutable => SingleElement("stopexecutable", true);
|
||||||
{
|
|
||||||
get
|
|
||||||
{
|
|
||||||
return SingleElement("stopexecutable", true);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Arguments or multiple optional argument elements which overrule the arguments element.
|
/// Arguments or multiple optional argument elements which overrule the arguments element.
|
||||||
|
@ -223,28 +206,17 @@ namespace winsw
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Multiple optional startargument elements.
|
/// Multiple optional startargument elements.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public string Startarguments
|
public string Startarguments => AppendTags("startargument", Defaults.Startarguments);
|
||||||
{
|
|
||||||
get
|
|
||||||
{
|
|
||||||
return AppendTags("startargument", Defaults.Startarguments);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Multiple optional stopargument elements.
|
/// Multiple optional stopargument elements.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public string Stoparguments
|
public string Stoparguments => AppendTags("stopargument", Defaults.Stoparguments);
|
||||||
|
|
||||||
|
public string WorkingDirectory
|
||||||
{
|
{
|
||||||
get
|
get
|
||||||
{
|
{
|
||||||
return AppendTags("stopargument", Defaults.Stoparguments);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
public string WorkingDirectory {
|
|
||||||
get {
|
|
||||||
var wd = SingleElement("workingdirectory", true);
|
var wd = SingleElement("workingdirectory", true);
|
||||||
return String.IsNullOrEmpty(wd) ? Defaults.WorkingDirectory : wd;
|
return String.IsNullOrEmpty(wd) ? Defaults.WorkingDirectory : wd;
|
||||||
}
|
}
|
||||||
|
@ -257,8 +229,8 @@ namespace winsw
|
||||||
List<string> res = new List<string>();
|
List<string> res = new List<string>();
|
||||||
|
|
||||||
XmlNode argumentNode = ExtensionsConfiguration;
|
XmlNode argumentNode = ExtensionsConfiguration;
|
||||||
XmlNodeList extensions = argumentNode != null ? argumentNode.SelectNodes("extension") : null;
|
XmlNodeList extensions = argumentNode?.SelectNodes("extension");
|
||||||
if ( extensions != null)
|
if (extensions != null)
|
||||||
{
|
{
|
||||||
foreach (XmlNode e in extensions)
|
foreach (XmlNode e in extensions)
|
||||||
{
|
{
|
||||||
|
@ -272,14 +244,7 @@ namespace winsw
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public XmlNode ExtensionsConfiguration
|
public XmlNode ExtensionsConfiguration => dom.SelectSingleNode("//extensions");
|
||||||
{
|
|
||||||
get
|
|
||||||
{
|
|
||||||
XmlNode argumentNode = dom.SelectSingleNode("//extensions");
|
|
||||||
return argumentNode;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Combines the contents of all the elements of the given name,
|
/// Combines the contents of all the elements of the given name,
|
||||||
|
@ -295,7 +260,7 @@ namespace winsw
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
string arguments = "";
|
string arguments = string.Empty;
|
||||||
|
|
||||||
foreach (XmlElement argument in dom.SelectNodes("//" + tagName))
|
foreach (XmlElement argument in dom.SelectNodes("//" + tagName))
|
||||||
{
|
{
|
||||||
|
@ -314,6 +279,7 @@ namespace winsw
|
||||||
token = '"' + token + '"';
|
token = '"' + token + '"';
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
arguments += " " + token;
|
arguments += " " + token;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -365,6 +331,7 @@ namespace winsw
|
||||||
{
|
{
|
||||||
mode = Defaults.LogMode;
|
mode = Defaults.LogMode;
|
||||||
}
|
}
|
||||||
|
|
||||||
return mode;
|
return mode;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -379,18 +346,9 @@ namespace winsw
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public bool OutFileDisabled
|
public bool OutFileDisabled => SingleBoolElement("outfiledisabled", Defaults.OutFileDisabled);
|
||||||
{
|
|
||||||
get { return SingleBoolElement("outfiledisabled", Defaults.OutFileDisabled); }
|
|
||||||
}
|
|
||||||
|
|
||||||
public bool ErrFileDisabled
|
public bool ErrFileDisabled => SingleBoolElement("errfiledisabled", Defaults.ErrFileDisabled);
|
||||||
{
|
|
||||||
get
|
|
||||||
{
|
|
||||||
return SingleBoolElement("errfiledisabled", Defaults.ErrFileDisabled);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public string OutFilePattern
|
public string OutFilePattern
|
||||||
{
|
{
|
||||||
|
@ -414,7 +372,6 @@ namespace winsw
|
||||||
|
|
||||||
public LogHandler LogHandler
|
public LogHandler LogHandler
|
||||||
{
|
{
|
||||||
|
|
||||||
get
|
get
|
||||||
{
|
{
|
||||||
XmlElement e = (XmlElement)dom.SelectSingleNode("//logmode");
|
XmlElement e = (XmlElement)dom.SelectSingleNode("//logmode");
|
||||||
|
@ -423,6 +380,7 @@ namespace winsw
|
||||||
// this is more modern way, to support nested elements as configuration
|
// this is more modern way, to support nested elements as configuration
|
||||||
e = (XmlElement)dom.SelectSingleNode("//log");
|
e = (XmlElement)dom.SelectSingleNode("//log");
|
||||||
}
|
}
|
||||||
|
|
||||||
int sizeThreshold;
|
int sizeThreshold;
|
||||||
switch (LogMode)
|
switch (LogMode)
|
||||||
{
|
{
|
||||||
|
@ -444,13 +402,14 @@ namespace winsw
|
||||||
{
|
{
|
||||||
throw new InvalidDataException("Time Based rolling policy is specified but no pattern can be found in configuration XML.");
|
throw new InvalidDataException("Time Based rolling policy is specified but no pattern can be found in configuration XML.");
|
||||||
}
|
}
|
||||||
|
|
||||||
var pattern = patternNode.InnerText;
|
var pattern = patternNode.InnerText;
|
||||||
int period = SingleIntElement(e,"period",1);
|
int period = SingleIntElement(e, "period", 1);
|
||||||
return new TimeBasedRollingLogAppender(LogDirectory, LogName, OutFileDisabled, ErrFileDisabled, OutFilePattern, ErrFilePattern, pattern, period);
|
return new TimeBasedRollingLogAppender(LogDirectory, LogName, OutFileDisabled, ErrFileDisabled, OutFilePattern, ErrFilePattern, pattern, period);
|
||||||
|
|
||||||
case "roll-by-size":
|
case "roll-by-size":
|
||||||
sizeThreshold = SingleIntElement(e,"sizeThreshold",10*1024) * SizeBasedRollingLogAppender.BYTES_PER_KB;
|
sizeThreshold = SingleIntElement(e, "sizeThreshold", 10 * 1024) * SizeBasedRollingLogAppender.BYTES_PER_KB;
|
||||||
int keepFiles = SingleIntElement(e,"keepFiles",SizeBasedRollingLogAppender.DEFAULT_FILES_TO_KEEP);
|
int keepFiles = SingleIntElement(e, "keepFiles", SizeBasedRollingLogAppender.DEFAULT_FILES_TO_KEEP);
|
||||||
return new SizeBasedRollingLogAppender(LogDirectory, LogName, OutFileDisabled, ErrFileDisabled, OutFilePattern, ErrFilePattern, sizeThreshold, keepFiles);
|
return new SizeBasedRollingLogAppender(LogDirectory, LogName, OutFileDisabled, ErrFileDisabled, OutFilePattern, ErrFilePattern, sizeThreshold, keepFiles);
|
||||||
|
|
||||||
case "append":
|
case "append":
|
||||||
|
@ -463,29 +422,29 @@ namespace winsw
|
||||||
{
|
{
|
||||||
throw new InvalidDataException("Roll-Size-Time Based rolling policy is specified but no pattern can be found in configuration XML.");
|
throw new InvalidDataException("Roll-Size-Time Based rolling policy is specified but no pattern can be found in configuration XML.");
|
||||||
}
|
}
|
||||||
|
|
||||||
XmlNode autoRollAtTimeNode = e.SelectSingleNode("autoRollAtTime");
|
XmlNode autoRollAtTimeNode = e.SelectSingleNode("autoRollAtTime");
|
||||||
TimeSpan? autoRollAtTime = null;
|
TimeSpan? autoRollAtTime = null;
|
||||||
if (autoRollAtTimeNode != null)
|
if (autoRollAtTimeNode != null)
|
||||||
{
|
{
|
||||||
TimeSpan autoRollAtTimeValue;
|
|
||||||
// validate it
|
// validate it
|
||||||
if (!TimeSpan.TryParse(autoRollAtTimeNode.InnerText, out autoRollAtTimeValue))
|
if (!TimeSpan.TryParse(autoRollAtTimeNode.InnerText, out TimeSpan autoRollAtTimeValue))
|
||||||
throw new InvalidDataException("Roll-Size-Time Based rolling policy is specified but autoRollAtTime does not match the TimeSpan format HH:mm:ss found in configuration XML.");
|
throw new InvalidDataException("Roll-Size-Time Based rolling policy is specified but autoRollAtTime does not match the TimeSpan format HH:mm:ss found in configuration XML.");
|
||||||
autoRollAtTime = autoRollAtTimeValue;
|
autoRollAtTime = autoRollAtTimeValue;
|
||||||
}
|
}
|
||||||
|
|
||||||
XmlNode zipolderthannumdaysNode = e.SelectSingleNode("zipOlderThanNumDays");
|
XmlNode zipolderthannumdaysNode = e.SelectSingleNode("zipOlderThanNumDays");
|
||||||
int? zipolderthannumdays = null;
|
int? zipolderthannumdays = null;
|
||||||
if (zipolderthannumdaysNode != null)
|
if (zipolderthannumdaysNode != null)
|
||||||
{
|
{
|
||||||
int zipolderthannumdaysValue;
|
|
||||||
// validate it
|
// validate it
|
||||||
if (!int.TryParse(zipolderthannumdaysNode.InnerText, out zipolderthannumdaysValue))
|
if (!int.TryParse(zipolderthannumdaysNode.InnerText, out int zipolderthannumdaysValue))
|
||||||
throw new InvalidDataException("Roll-Size-Time Based rolling policy is specified but zipOlderThanNumDays does not match the int format found in configuration XML.");
|
throw new InvalidDataException("Roll-Size-Time Based rolling policy is specified but zipOlderThanNumDays does not match the int format found in configuration XML.");
|
||||||
zipolderthannumdays = zipolderthannumdaysValue;
|
zipolderthannumdays = zipolderthannumdaysValue;
|
||||||
}
|
}
|
||||||
|
|
||||||
XmlNode zipdateformatNode = e.SelectSingleNode("zipDateFormat");
|
XmlNode zipdateformatNode = e.SelectSingleNode("zipDateFormat");
|
||||||
string zipdateformat = null;
|
string zipdateformat;
|
||||||
if (zipdateformatNode == null)
|
if (zipdateformatNode == null)
|
||||||
{
|
{
|
||||||
zipdateformat = "yyyyMM";
|
zipdateformat = "yyyyMM";
|
||||||
|
@ -501,7 +460,6 @@ namespace winsw
|
||||||
throw new InvalidDataException("Undefined logging mode: " + LogMode);
|
throw new InvalidDataException("Undefined logging mode: " + LogMode);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
|
@ -519,35 +477,19 @@ namespace winsw
|
||||||
{
|
{
|
||||||
serviceDependencies.Add(depend.InnerText);
|
serviceDependencies.Add(depend.InnerText);
|
||||||
}
|
}
|
||||||
|
|
||||||
return (string[])serviceDependencies.ToArray(typeof(string));
|
return (string[])serviceDependencies.ToArray(typeof(string));
|
||||||
}
|
}
|
||||||
|
|
||||||
return Defaults.ServiceDependencies;
|
return Defaults.ServiceDependencies;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public string Id
|
public string Id => SingleElement("id");
|
||||||
{
|
|
||||||
get
|
|
||||||
{
|
|
||||||
return SingleElement("id");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public string Caption
|
public string Caption => SingleElement("name");
|
||||||
{
|
|
||||||
get
|
|
||||||
{
|
|
||||||
return SingleElement("name");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public string Description
|
public string Description => SingleElement("description");
|
||||||
{
|
|
||||||
get
|
|
||||||
{
|
|
||||||
return SingleElement("description");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Start mode of the Service
|
/// Start mode of the Service
|
||||||
|
@ -557,7 +499,9 @@ namespace winsw
|
||||||
get
|
get
|
||||||
{
|
{
|
||||||
var p = SingleElement("startmode", true);
|
var p = SingleElement("startmode", true);
|
||||||
if (p == null) return Defaults.StartMode;
|
if (p == null)
|
||||||
|
return Defaults.StartMode;
|
||||||
|
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
return (StartMode)Enum.Parse(typeof(StartMode), p, true);
|
return (StartMode)Enum.Parse(typeof(StartMode), p, true);
|
||||||
|
@ -569,6 +513,7 @@ namespace winsw
|
||||||
{
|
{
|
||||||
Console.WriteLine(sm);
|
Console.WriteLine(sm);
|
||||||
}
|
}
|
||||||
|
|
||||||
throw;
|
throw;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -578,64 +523,32 @@ namespace winsw
|
||||||
/// True if the service should be installed with the DelayedAutoStart flag.
|
/// True if the service should be installed with the DelayedAutoStart flag.
|
||||||
/// This setting will be applyed only during the install command and only when the Automatic start mode is configured.
|
/// This setting will be applyed only during the install command and only when the Automatic start mode is configured.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public bool DelayedAutoStart
|
public bool DelayedAutoStart => dom.SelectSingleNode("//delayedAutoStart") != null;
|
||||||
{
|
|
||||||
get
|
|
||||||
{
|
|
||||||
return dom.SelectSingleNode("//delayedAutoStart") != null;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// True if the service should beep when finished on shutdown.
|
/// True if the service should beep when finished on shutdown.
|
||||||
/// This doesn't work on some OSes. See http://msdn.microsoft.com/en-us/library/ms679277%28VS.85%29.aspx
|
/// This doesn't work on some OSes. See http://msdn.microsoft.com/en-us/library/ms679277%28VS.85%29.aspx
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public bool BeepOnShutdown
|
public bool BeepOnShutdown => dom.SelectSingleNode("//beeponshutdown") != null;
|
||||||
{
|
|
||||||
get
|
|
||||||
{
|
|
||||||
return dom.SelectSingleNode("//beeponshutdown") != null;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// The estimated time required for a pending stop operation (default 15 secs).
|
/// The estimated time required for a pending stop operation (default 15 secs).
|
||||||
/// Before the specified amount of time has elapsed, the service should make its next call to the SetServiceStatus function
|
/// Before the specified amount of time has elapsed, the service should make its next call to the SetServiceStatus function
|
||||||
/// with either an incremented checkPoint value or a change in currentState. (see http://msdn.microsoft.com/en-us/library/ms685996.aspx)
|
/// with either an incremented checkPoint value or a change in currentState. (see http://msdn.microsoft.com/en-us/library/ms685996.aspx)
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public TimeSpan WaitHint
|
public TimeSpan WaitHint => SingleTimeSpanElement(dom, "waithint", Defaults.WaitHint);
|
||||||
{
|
|
||||||
get
|
|
||||||
{
|
|
||||||
return SingleTimeSpanElement(dom, "waithint", Defaults.WaitHint);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// The time before the service should make its next call to the SetServiceStatus function
|
/// The time before the service should make its next call to the SetServiceStatus function
|
||||||
/// with an incremented checkPoint value (default 1 sec).
|
/// with an incremented checkPoint value (default 1 sec).
|
||||||
/// Do not wait longer than the wait hint. A good interval is one-tenth of the wait hint but not less than 1 second and not more than 10 seconds.
|
/// Do not wait longer than the wait hint. A good interval is one-tenth of the wait hint but not less than 1 second and not more than 10 seconds.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public TimeSpan SleepTime
|
public TimeSpan SleepTime => SingleTimeSpanElement(dom, "sleeptime", Defaults.SleepTime);
|
||||||
{
|
|
||||||
get
|
|
||||||
{
|
|
||||||
return SingleTimeSpanElement(dom, "sleeptime", Defaults.SleepTime);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// True if the service can interact with the desktop.
|
/// True if the service can interact with the desktop.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public bool Interactive
|
public bool Interactive => dom.SelectSingleNode("//interactive") != null;
|
||||||
{
|
|
||||||
get
|
|
||||||
{
|
|
||||||
return dom.SelectSingleNode("//interactive") != null;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Environment variable overrides
|
/// Environment variable overrides
|
||||||
|
@ -653,6 +566,7 @@ namespace winsw
|
||||||
|
|
||||||
Environment.SetEnvironmentVariable(key, value);
|
Environment.SetEnvironmentVariable(key, value);
|
||||||
}
|
}
|
||||||
|
|
||||||
return map;
|
return map;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -674,12 +588,12 @@ namespace winsw
|
||||||
List<Download> r = new List<Download>();
|
List<Download> r = new List<Download>();
|
||||||
foreach (XmlNode n in xmlNodeList)
|
foreach (XmlNode n in xmlNodeList)
|
||||||
{
|
{
|
||||||
XmlElement el = n as XmlElement;
|
if (n is XmlElement el)
|
||||||
if (el != null)
|
|
||||||
{
|
{
|
||||||
r.Add(new Download(el));
|
r.Add(new Download(el));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return r;
|
return r;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -710,21 +624,17 @@ namespace winsw
|
||||||
default:
|
default:
|
||||||
throw new Exception("Invalid failure action: " + action);
|
throw new Exception("Invalid failure action: " + action);
|
||||||
}
|
}
|
||||||
|
|
||||||
XmlAttribute delay = n.Attributes["delay"];
|
XmlAttribute delay = n.Attributes["delay"];
|
||||||
r.Add(new SC_ACTION(type, delay != null ? ParseTimeSpan(delay.Value) : TimeSpan.Zero));
|
r.Add(new SC_ACTION(type, delay != null ? ParseTimeSpan(delay.Value) : TimeSpan.Zero));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return r;
|
return r;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public TimeSpan ResetFailureAfter
|
public TimeSpan ResetFailureAfter => SingleTimeSpanElement(dom, "resetfailure", Defaults.ResetFailureAfter);
|
||||||
{
|
|
||||||
get
|
|
||||||
{
|
|
||||||
return SingleTimeSpanElement(dom, "resetfailure", Defaults.ResetFailureAfter);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
protected string GetServiceAccountPart(string subNodeName)
|
protected string GetServiceAccountPart(string subNodeName)
|
||||||
{
|
{
|
||||||
|
@ -740,47 +650,19 @@ namespace winsw
|
||||||
}
|
}
|
||||||
|
|
||||||
return null;
|
return null;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
protected string AllowServiceLogon
|
protected string AllowServiceLogon => GetServiceAccountPart("allowservicelogon");
|
||||||
{
|
|
||||||
get
|
|
||||||
{
|
|
||||||
return GetServiceAccountPart("allowservicelogon");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// ReSharper disable once InconsistentNaming
|
// ReSharper disable once InconsistentNaming
|
||||||
protected string serviceAccountDomain
|
protected string serviceAccountDomain => GetServiceAccountPart("domain");
|
||||||
{
|
|
||||||
get
|
|
||||||
{
|
|
||||||
return GetServiceAccountPart("domain");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// ReSharper disable once InconsistentNaming
|
// ReSharper disable once InconsistentNaming
|
||||||
protected string serviceAccountName
|
protected string serviceAccountName => GetServiceAccountPart("user");
|
||||||
{
|
|
||||||
get
|
|
||||||
{
|
|
||||||
return GetServiceAccountPart("user");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public string ServiceAccountPassword
|
public string ServiceAccountPassword => GetServiceAccountPart("password");
|
||||||
{
|
|
||||||
get
|
|
||||||
{
|
|
||||||
return GetServiceAccountPart("password");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public string ServiceAccountUser
|
public string ServiceAccountUser => (serviceAccountDomain ?? "NULL") + @"\" + (serviceAccountName ?? "NULL");
|
||||||
{
|
|
||||||
get { return (serviceAccountDomain ?? "NULL") + @"\" + (serviceAccountName ?? "NULL"); }
|
|
||||||
}
|
|
||||||
|
|
||||||
public bool HasServiceAccount()
|
public bool HasServiceAccount()
|
||||||
{
|
{
|
||||||
|
@ -793,12 +675,12 @@ namespace winsw
|
||||||
{
|
{
|
||||||
if (AllowServiceLogon != null)
|
if (AllowServiceLogon != null)
|
||||||
{
|
{
|
||||||
bool parsedvalue;
|
if (Boolean.TryParse(AllowServiceLogon, out bool parsedvalue))
|
||||||
if (Boolean.TryParse(AllowServiceLogon, out parsedvalue))
|
|
||||||
{
|
{
|
||||||
return parsedvalue;
|
return parsedvalue;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -806,24 +688,18 @@ namespace winsw
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Time to wait for the service to gracefully shutdown the executable before we forcibly kill it
|
/// Time to wait for the service to gracefully shutdown the executable before we forcibly kill it
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public TimeSpan StopTimeout
|
public TimeSpan StopTimeout => SingleTimeSpanElement(dom, "stoptimeout", Defaults.StopTimeout);
|
||||||
{
|
|
||||||
get
|
|
||||||
{
|
|
||||||
return SingleTimeSpanElement(dom, "stoptimeout", Defaults.StopTimeout);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public bool StopParentProcessFirst
|
public bool StopParentProcessFirst
|
||||||
{
|
{
|
||||||
get
|
get
|
||||||
{
|
{
|
||||||
var value = SingleElement("stopparentprocessfirst", true);
|
var value = SingleElement("stopparentprocessfirst", true);
|
||||||
bool result;
|
if (bool.TryParse(value, out bool result))
|
||||||
if (bool.TryParse(value, out result))
|
|
||||||
{
|
{
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
return Defaults.StopParentProcessFirst;
|
return Defaults.StopParentProcessFirst;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -835,8 +711,9 @@ namespace winsw
|
||||||
{
|
{
|
||||||
get
|
get
|
||||||
{
|
{
|
||||||
var p = SingleElement("priority",true);
|
var p = SingleElement("priority", true);
|
||||||
if (p == null) return Defaults.Priority;
|
if (p == null)
|
||||||
|
return Defaults.Priority;
|
||||||
|
|
||||||
return (ProcessPriorityClass)Enum.Parse(typeof(ProcessPriorityClass), p, true);
|
return (ProcessPriorityClass)Enum.Parse(typeof(ProcessPriorityClass), p, true);
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,10 +1,9 @@
|
||||||
using log4net;
|
using System;
|
||||||
using System;
|
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Diagnostics;
|
using System.Diagnostics;
|
||||||
using System.Management;
|
using System.Management;
|
||||||
using System.Text;
|
|
||||||
using System.Threading;
|
using System.Threading;
|
||||||
|
using log4net;
|
||||||
|
|
||||||
namespace winsw.Util
|
namespace winsw.Util
|
||||||
{
|
{
|
||||||
|
@ -25,7 +24,8 @@ namespace winsw.Util
|
||||||
{
|
{
|
||||||
var childPids = new List<int>();
|
var childPids = new List<int>();
|
||||||
|
|
||||||
try {
|
try
|
||||||
|
{
|
||||||
var searcher = new ManagementObjectSearcher("Select * From Win32_Process Where ParentProcessID=" + pid);
|
var searcher = new ManagementObjectSearcher("Select * From Win32_Process Where ParentProcessID=" + pid);
|
||||||
foreach (var mo in searcher.Get())
|
foreach (var mo in searcher.Get())
|
||||||
{
|
{
|
||||||
|
@ -87,7 +87,7 @@ namespace winsw.Util
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
//TODO: Propagate error if process kill fails? Currently we use the legacy behavior
|
// TODO: Propagate error if process kill fails? Currently we use the legacy behavior
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
|
@ -172,7 +172,7 @@ namespace winsw.Util
|
||||||
// monitor the completion of the process
|
// monitor the completion of the process
|
||||||
if (callback != null)
|
if (callback != null)
|
||||||
{
|
{
|
||||||
StartThread(delegate
|
StartThread(() =>
|
||||||
{
|
{
|
||||||
processToStart.WaitForExit();
|
processToStart.WaitForExit();
|
||||||
callback(processToStart);
|
callback(processToStart);
|
||||||
|
@ -187,7 +187,7 @@ namespace winsw.Util
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public static void StartThread(ThreadStart main)
|
public static void StartThread(ThreadStart main)
|
||||||
{
|
{
|
||||||
new Thread(delegate()
|
new Thread(() =>
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
using log4net;
|
using System;
|
||||||
using System;
|
|
||||||
using System.Diagnostics;
|
using System.Diagnostics;
|
||||||
using System.Runtime.InteropServices;
|
using System.Runtime.InteropServices;
|
||||||
|
using log4net;
|
||||||
using winsw.Native;
|
using winsw.Native;
|
||||||
|
|
||||||
namespace winsw.Util
|
namespace winsw.Util
|
||||||
|
@ -20,6 +20,7 @@ namespace winsw.Util
|
||||||
|
|
||||||
[DllImport(KERNEL32)]
|
[DllImport(KERNEL32)]
|
||||||
private static extern bool SetConsoleCtrlHandler(ConsoleCtrlDelegate HandlerRoutine, bool Add);
|
private static extern bool SetConsoleCtrlHandler(ConsoleCtrlDelegate HandlerRoutine, bool Add);
|
||||||
|
|
||||||
// Delegate type to be used as the Handler Routine for SCCH
|
// Delegate type to be used as the Handler Routine for SCCH
|
||||||
private delegate Boolean ConsoleCtrlDelegate(CtrlTypes CtrlType);
|
private delegate Boolean ConsoleCtrlDelegate(CtrlTypes CtrlType);
|
||||||
|
|
||||||
|
@ -47,7 +48,7 @@ namespace winsw.Util
|
||||||
{
|
{
|
||||||
if (AttachConsole((uint)process.Id))
|
if (AttachConsole((uint)process.Id))
|
||||||
{
|
{
|
||||||
//Disable Ctrl-C handling for our program
|
// Disable Ctrl-C handling for our program
|
||||||
SetConsoleCtrlHandler(null, true);
|
SetConsoleCtrlHandler(null, true);
|
||||||
GenerateConsoleCtrlEvent(CtrlTypes.CTRL_C_EVENT, 0);
|
GenerateConsoleCtrlEvent(CtrlTypes.CTRL_C_EVENT, 0);
|
||||||
|
|
||||||
|
|
|
@ -1,8 +1,6 @@
|
||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
|
||||||
using System.Text;
|
|
||||||
using System.Xml;
|
|
||||||
using System.IO;
|
using System.IO;
|
||||||
|
using System.Xml;
|
||||||
|
|
||||||
namespace winsw.Util
|
namespace winsw.Util
|
||||||
{
|
{
|
||||||
|
@ -19,7 +17,9 @@ namespace winsw.Util
|
||||||
public static string SingleElement(XmlNode node, string tagName, Boolean optional)
|
public static string SingleElement(XmlNode node, string tagName, Boolean optional)
|
||||||
{
|
{
|
||||||
var n = node.SelectSingleNode(tagName);
|
var n = node.SelectSingleNode(tagName);
|
||||||
if (n == null && !optional) throw new InvalidDataException("<" + tagName + "> is missing in configuration XML");
|
if (n == null && !optional)
|
||||||
|
throw new InvalidDataException("<" + tagName + "> is missing in configuration XML");
|
||||||
|
|
||||||
return n == null ? null : Environment.ExpandEnvironmentVariables(n.InnerText);
|
return n == null ? null : Environment.ExpandEnvironmentVariables(n.InnerText);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -34,7 +34,9 @@ namespace winsw.Util
|
||||||
public static XmlNode SingleNode(XmlNode node, string tagName, Boolean optional)
|
public static XmlNode SingleNode(XmlNode node, string tagName, Boolean optional)
|
||||||
{
|
{
|
||||||
var n = node.SelectSingleNode(tagName);
|
var n = node.SelectSingleNode(tagName);
|
||||||
if (n == null && !optional) throw new InvalidDataException("<" + tagName + "> is missing in configuration XML");
|
if (n == null && !optional)
|
||||||
|
throw new InvalidDataException("<" + tagName + "> is missing in configuration XML");
|
||||||
|
|
||||||
return n;
|
return n;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -45,14 +47,14 @@ namespace winsw.Util
|
||||||
/// <param name="attributeName">Attribute name</param>
|
/// <param name="attributeName">Attribute name</param>
|
||||||
/// <returns>Attribute value</returns>
|
/// <returns>Attribute value</returns>
|
||||||
/// <exception cref="InvalidDataException">The required attribute is missing</exception>
|
/// <exception cref="InvalidDataException">The required attribute is missing</exception>
|
||||||
public static TAttributeType SingleAttribute <TAttributeType> (XmlElement node, string attributeName)
|
public static TAttributeType SingleAttribute<TAttributeType>(XmlElement node, string attributeName)
|
||||||
{
|
{
|
||||||
if (!node.HasAttribute(attributeName))
|
if (!node.HasAttribute(attributeName))
|
||||||
{
|
{
|
||||||
throw new InvalidDataException("Attribute <" + attributeName + "> is missing in configuration XML");
|
throw new InvalidDataException("Attribute <" + attributeName + "> is missing in configuration XML");
|
||||||
}
|
}
|
||||||
|
|
||||||
return SingleAttribute<TAttributeType>(node, attributeName, default(TAttributeType));
|
return SingleAttribute(node, attributeName, default(TAttributeType));
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
|
@ -64,7 +66,8 @@ namespace winsw.Util
|
||||||
/// <returns>Attribute value (or default)</returns>
|
/// <returns>Attribute value (or default)</returns>
|
||||||
public static TAttributeType SingleAttribute<TAttributeType>(XmlElement node, string attributeName, TAttributeType defaultValue)
|
public static TAttributeType SingleAttribute<TAttributeType>(XmlElement node, string attributeName, TAttributeType defaultValue)
|
||||||
{
|
{
|
||||||
if (!node.HasAttribute(attributeName)) return defaultValue;
|
if (!node.HasAttribute(attributeName))
|
||||||
|
return defaultValue;
|
||||||
|
|
||||||
string rawValue = node.GetAttribute(attributeName);
|
string rawValue = node.GetAttribute(attributeName);
|
||||||
string substitutedValue = Environment.ExpandEnvironmentVariables(rawValue);
|
string substitutedValue = Environment.ExpandEnvironmentVariables(rawValue);
|
||||||
|
@ -83,7 +86,8 @@ namespace winsw.Util
|
||||||
/// <exception cref="InvalidDataException">Wrong enum value</exception>
|
/// <exception cref="InvalidDataException">Wrong enum value</exception>
|
||||||
public static TAttributeType EnumAttribute<TAttributeType>(XmlElement node, string attributeName, TAttributeType defaultValue)
|
public static TAttributeType EnumAttribute<TAttributeType>(XmlElement node, string attributeName, TAttributeType defaultValue)
|
||||||
{
|
{
|
||||||
if (!node.HasAttribute(attributeName)) return defaultValue;
|
if (!node.HasAttribute(attributeName))
|
||||||
|
return defaultValue;
|
||||||
|
|
||||||
string rawValue = node.GetAttribute(attributeName);
|
string rawValue = node.GetAttribute(attributeName);
|
||||||
string substitutedValue = Environment.ExpandEnvironmentVariables(rawValue);
|
string substitutedValue = Environment.ExpandEnvironmentVariables(rawValue);
|
||||||
|
|
|
@ -1,6 +1,4 @@
|
||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
|
||||||
using System.Text;
|
|
||||||
|
|
||||||
namespace winsw
|
namespace winsw
|
||||||
{
|
{
|
||||||
|
|
|
@ -1,8 +1,4 @@
|
||||||
using System;
|
namespace winsw
|
||||||
using System.Collections.Generic;
|
|
||||||
using System.Text;
|
|
||||||
|
|
||||||
namespace winsw
|
|
||||||
{
|
{
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Class, which contains generic information about WinSW runtime.
|
/// Class, which contains generic information about WinSW runtime.
|
||||||
|
@ -19,11 +15,11 @@ namespace winsw
|
||||||
/// Variable, which points to the service ID.
|
/// Variable, which points to the service ID.
|
||||||
/// It may be used to determine runaway processes.
|
/// It may be used to determine runaway processes.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public static string ENVVAR_NAME_SERVICE_ID { get { return SYSTEM_EVNVVAR_PREFIX + "SERVICE_ID"; } }
|
public static string ENVVAR_NAME_SERVICE_ID => SYSTEM_EVNVVAR_PREFIX + "SERVICE_ID";
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Variable, which specifies path to the executable being launched by WinSW.
|
/// Variable, which specifies path to the executable being launched by WinSW.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public static string ENVVAR_NAME_EXECUTABLE_PATH { get { return SYSTEM_EVNVVAR_PREFIX + "EXECUTABLE"; } }
|
public static string ENVVAR_NAME_EXECUTABLE_PATH => SYSTEM_EVNVVAR_PREFIX + "EXECUTABLE";
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -5,7 +5,7 @@ using DynamicProxy;
|
||||||
|
|
||||||
namespace WMI
|
namespace WMI
|
||||||
{
|
{
|
||||||
//Reference: http://msdn2.microsoft.com/en-us/library/aa389390(VS.85).aspx
|
// Reference: http://msdn2.microsoft.com/en-us/library/aa389390(VS.85).aspx
|
||||||
|
|
||||||
public enum ReturnValue
|
public enum ReturnValue
|
||||||
{
|
{
|
||||||
|
@ -63,13 +63,14 @@ namespace WMI
|
||||||
public class WmiClassName : Attribute
|
public class WmiClassName : Attribute
|
||||||
{
|
{
|
||||||
public readonly string Name;
|
public readonly string Name;
|
||||||
public WmiClassName(string name) { Name = name; }
|
|
||||||
|
public WmiClassName(string name) => Name = name;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Marker interface to denote a collection in WMI.
|
/// Marker interface to denote a collection in WMI.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public interface IWmiCollection {}
|
public interface IWmiCollection { }
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Marker interface to denote an individual managed object
|
/// Marker interface to denote an individual managed object
|
||||||
|
@ -141,6 +142,7 @@ namespace WMI
|
||||||
_mo[method.Name.Substring(4)] = args[0];
|
_mo[method.Name.Substring(4)] = args[0];
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (method.Name.StartsWith("get_"))
|
if (method.Name.StartsWith("get_"))
|
||||||
{
|
{
|
||||||
return _mo[method.Name.Substring(4)];
|
return _mo[method.Name.Substring(4)];
|
||||||
|
@ -180,7 +182,9 @@ namespace WMI
|
||||||
string query = "SELECT * FROM " + _wmiClass + " WHERE ";
|
string query = "SELECT * FROM " + _wmiClass + " WHERE ";
|
||||||
for (int i = 0; i < args.Length; i++)
|
for (int i = 0; i < args.Length; i++)
|
||||||
{
|
{
|
||||||
if (i != 0) query += " AND ";
|
if (i != 0)
|
||||||
|
query += " AND ";
|
||||||
|
|
||||||
query += ' ' + Capitalize(methodArgs[i].Name) + " = '" + args[i] + "'";
|
query += ' ' + Capitalize(methodArgs[i].Name) + " = '" + args[i] + "'";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,12 +1,12 @@
|
||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Specialized;
|
||||||
using System.Xml;
|
|
||||||
using System.Diagnostics;
|
using System.Diagnostics;
|
||||||
|
using System.IO;
|
||||||
|
using System.Text;
|
||||||
|
using System.Xml;
|
||||||
|
using log4net;
|
||||||
using winsw.Extensions;
|
using winsw.Extensions;
|
||||||
using winsw.Util;
|
using winsw.Util;
|
||||||
using log4net;
|
|
||||||
using System.Collections.Specialized;
|
|
||||||
using System.Text;
|
|
||||||
|
|
||||||
namespace winsw.Plugins.RunawayProcessKiller
|
namespace winsw.Plugins.RunawayProcessKiller
|
||||||
{
|
{
|
||||||
|
@ -34,7 +34,7 @@ namespace winsw.Plugins.RunawayProcessKiller
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public bool CheckWinSWEnvironmentVariable { get; private set; }
|
public bool CheckWinSWEnvironmentVariable { get; private set; }
|
||||||
|
|
||||||
public override String DisplayName { get { return "Runaway Process Killer"; } }
|
public override String DisplayName => "Runaway Process Killer";
|
||||||
|
|
||||||
private String ServiceId { get; set; }
|
private String ServiceId { get; set; }
|
||||||
|
|
||||||
|
@ -61,7 +61,7 @@ namespace winsw.Plugins.RunawayProcessKiller
|
||||||
StopTimeout = TimeSpan.FromMilliseconds(Int32.Parse(XmlHelper.SingleElement(node, "stopTimeout", false)));
|
StopTimeout = TimeSpan.FromMilliseconds(Int32.Parse(XmlHelper.SingleElement(node, "stopTimeout", false)));
|
||||||
StopParentProcessFirst = Boolean.Parse(XmlHelper.SingleElement(node, "stopParentFirst", false));
|
StopParentProcessFirst = Boolean.Parse(XmlHelper.SingleElement(node, "stopParentFirst", false));
|
||||||
ServiceId = descriptor.Id;
|
ServiceId = descriptor.Id;
|
||||||
//TODO: Consider making it documented
|
// TODO: Consider making it documented
|
||||||
var checkWinSWEnvironmentVariable = XmlHelper.SingleElement(node, "checkWinSWEnvironmentVariable", true);
|
var checkWinSWEnvironmentVariable = XmlHelper.SingleElement(node, "checkWinSWEnvironmentVariable", true);
|
||||||
CheckWinSWEnvironmentVariable = checkWinSWEnvironmentVariable != null ? Boolean.Parse(checkWinSWEnvironmentVariable) : true;
|
CheckWinSWEnvironmentVariable = checkWinSWEnvironmentVariable != null ? Boolean.Parse(checkWinSWEnvironmentVariable) : true;
|
||||||
}
|
}
|
||||||
|
@ -74,17 +74,19 @@ namespace winsw.Plugins.RunawayProcessKiller
|
||||||
{
|
{
|
||||||
// Read PID file from the disk
|
// Read PID file from the disk
|
||||||
int pid;
|
int pid;
|
||||||
if (System.IO.File.Exists(Pidfile)) {
|
if (File.Exists(Pidfile))
|
||||||
|
{
|
||||||
string pidstring;
|
string pidstring;
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
pidstring = System.IO.File.ReadAllText(Pidfile);
|
pidstring = File.ReadAllText(Pidfile);
|
||||||
}
|
}
|
||||||
catch (Exception ex)
|
catch (Exception ex)
|
||||||
{
|
{
|
||||||
Logger.Error("Cannot read PID file from " + Pidfile, ex);
|
Logger.Error("Cannot read PID file from " + Pidfile, ex);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
pid = Int32.Parse(pidstring);
|
pid = Int32.Parse(pidstring);
|
||||||
|
@ -108,7 +110,7 @@ namespace winsw.Plugins.RunawayProcessKiller
|
||||||
{
|
{
|
||||||
proc = Process.GetProcessById(pid);
|
proc = Process.GetProcessById(pid);
|
||||||
}
|
}
|
||||||
catch (ArgumentException ex)
|
catch (ArgumentException)
|
||||||
{
|
{
|
||||||
Logger.Debug("No runaway process with PID=" + pid + ". The process has been already stopped.");
|
Logger.Debug("No runaway process with PID=" + pid + ". The process has been already stopped.");
|
||||||
return;
|
return;
|
||||||
|
@ -129,12 +131,14 @@ namespace winsw.Plugins.RunawayProcessKiller
|
||||||
{
|
{
|
||||||
Logger.Warn("The process " + pid + " has no " + expectedEnvVarName + " environment variable defined. "
|
Logger.Warn("The process " + pid + " has no " + expectedEnvVarName + " environment variable defined. "
|
||||||
+ "The process has not been started by WinSW, hence it won't be terminated.");
|
+ "The process has not been started by WinSW, hence it won't be terminated.");
|
||||||
if (Logger.IsDebugEnabled) {
|
if (Logger.IsDebugEnabled)
|
||||||
//TODO replace by String.Join() in .NET 4
|
{
|
||||||
|
// TODO replace by String.Join() in .NET 4
|
||||||
String[] keys = new String[previousProcessEnvVars.Count];
|
String[] keys = new String[previousProcessEnvVars.Count];
|
||||||
previousProcessEnvVars.Keys.CopyTo(keys, 0);
|
previousProcessEnvVars.Keys.CopyTo(keys, 0);
|
||||||
Logger.DebugFormat("Env vars of the process with PID={0}: {1}", new Object[] {pid, String.Join(",", keys)});
|
Logger.DebugFormat("Env vars of the process with PID={0}: {1}", new Object[] { pid, String.Join(",", keys) });
|
||||||
}
|
}
|
||||||
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
|
@ -155,11 +159,13 @@ namespace winsw.Plugins.RunawayProcessKiller
|
||||||
StringBuilder bldr = new StringBuilder("Stopping the runaway process (pid=");
|
StringBuilder bldr = new StringBuilder("Stopping the runaway process (pid=");
|
||||||
bldr.Append(pid);
|
bldr.Append(pid);
|
||||||
bldr.Append(") and its children. Environment was ");
|
bldr.Append(") and its children. Environment was ");
|
||||||
if (!CheckWinSWEnvironmentVariable) {
|
if (!CheckWinSWEnvironmentVariable)
|
||||||
|
{
|
||||||
bldr.Append("not ");
|
bldr.Append("not ");
|
||||||
}
|
}
|
||||||
|
|
||||||
bldr.Append("checked, affiliated service ID: ");
|
bldr.Append("checked, affiliated service ID: ");
|
||||||
bldr.Append(affiliatedServiceId != null ? affiliatedServiceId : "undefined");
|
bldr.Append(affiliatedServiceId ?? "undefined");
|
||||||
bldr.Append(", process to kill: ");
|
bldr.Append(", process to kill: ");
|
||||||
bldr.Append(proc);
|
bldr.Append(proc);
|
||||||
|
|
||||||
|
@ -171,12 +177,12 @@ namespace winsw.Plugins.RunawayProcessKiller
|
||||||
/// Records the started process PID for the future use in OnStart() after the restart.
|
/// Records the started process PID for the future use in OnStart() after the restart.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="process"></param>
|
/// <param name="process"></param>
|
||||||
public override void OnProcessStarted(System.Diagnostics.Process process)
|
public override void OnProcessStarted(Process process)
|
||||||
{
|
{
|
||||||
Logger.Info("Recording PID of the started process:" + process.Id + ". PID file destination is " + Pidfile);
|
Logger.Info("Recording PID of the started process:" + process.Id + ". PID file destination is " + Pidfile);
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
System.IO.File.WriteAllText(Pidfile, process.Id.ToString());
|
File.WriteAllText(Pidfile, process.Id.ToString());
|
||||||
}
|
}
|
||||||
catch (Exception ex)
|
catch (Exception ex)
|
||||||
{
|
{
|
||||||
|
|
|
@ -1,10 +1,9 @@
|
||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Xml;
|
using System.Xml;
|
||||||
using System.Diagnostics;
|
using log4net;
|
||||||
using winsw.Extensions;
|
using winsw.Extensions;
|
||||||
using winsw.Util;
|
using winsw.Util;
|
||||||
using log4net;
|
|
||||||
|
|
||||||
namespace winsw.Plugins.SharedDirectoryMapper
|
namespace winsw.Plugins.SharedDirectoryMapper
|
||||||
{
|
{
|
||||||
|
@ -13,7 +12,7 @@ namespace winsw.Plugins.SharedDirectoryMapper
|
||||||
private readonly SharedDirectoryMappingHelper _mapper = new SharedDirectoryMappingHelper();
|
private readonly SharedDirectoryMappingHelper _mapper = new SharedDirectoryMappingHelper();
|
||||||
private readonly List<SharedDirectoryMapperConfig> _entries = new List<SharedDirectoryMapperConfig>();
|
private readonly List<SharedDirectoryMapperConfig> _entries = new List<SharedDirectoryMapperConfig>();
|
||||||
|
|
||||||
public override String DisplayName { get { return "Shared Directory Mapper"; } }
|
public override String DisplayName => "Shared Directory Mapper";
|
||||||
|
|
||||||
private static readonly ILog Logger = LogManager.GetLogger(typeof(SharedDirectoryMapper));
|
private static readonly ILog Logger = LogManager.GetLogger(typeof(SharedDirectoryMapper));
|
||||||
|
|
||||||
|
@ -34,8 +33,7 @@ namespace winsw.Plugins.SharedDirectoryMapper
|
||||||
{
|
{
|
||||||
foreach (XmlNode mapNode in nodes)
|
foreach (XmlNode mapNode in nodes)
|
||||||
{
|
{
|
||||||
var mapElement = mapNode as XmlElement;
|
if (mapNode is XmlElement mapElement)
|
||||||
if (mapElement != null)
|
|
||||||
{
|
{
|
||||||
var config = SharedDirectoryMapperConfig.FromXml(mapElement);
|
var config = SharedDirectoryMapperConfig.FromXml(mapElement);
|
||||||
_entries.Add(config);
|
_entries.Add(config);
|
||||||
|
@ -85,7 +83,8 @@ namespace winsw.Plugins.SharedDirectoryMapper
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void HandleMappingError(SharedDirectoryMapperConfig config, MapperException ex) {
|
private void HandleMappingError(SharedDirectoryMapperConfig config, MapperException ex)
|
||||||
|
{
|
||||||
Logger.Error("Mapping of " + config.Label + " failed. STDOUT: " + ex.Process.StandardOutput.ReadToEnd()
|
Logger.Error("Mapping of " + config.Label + " failed. STDOUT: " + ex.Process.StandardOutput.ReadToEnd()
|
||||||
+ " \r\nSTDERR: " + ex.Process.StandardError.ReadToEnd(), ex);
|
+ " \r\nSTDERR: " + ex.Process.StandardError.ReadToEnd(), ex);
|
||||||
throw new ExtensionException(Descriptor.Id, DisplayName + ": Mapping of " + config.Label + "failed", ex);
|
throw new ExtensionException(Descriptor.Id, DisplayName + ": Mapping of " + config.Label + "failed", ex);
|
||||||
|
|
|
@ -1,6 +1,5 @@
|
||||||
using System;
|
using System;
|
||||||
using System.Diagnostics;
|
using System.Diagnostics;
|
||||||
using winsw.Util;
|
|
||||||
|
|
||||||
namespace winsw.Plugins.SharedDirectoryMapper
|
namespace winsw.Plugins.SharedDirectoryMapper
|
||||||
{
|
{
|
||||||
|
|
|
@ -1,9 +1,6 @@
|
||||||
using NUnit.Framework;
|
using System.IO;
|
||||||
using System;
|
|
||||||
using System.Collections.Generic;
|
|
||||||
using System.IO;
|
|
||||||
using System.Text;
|
|
||||||
using System.Xml;
|
using System.Xml;
|
||||||
|
using NUnit.Framework;
|
||||||
using winsw;
|
using winsw;
|
||||||
using winswTests.Util;
|
using winswTests.Util;
|
||||||
|
|
||||||
|
@ -16,11 +13,10 @@ namespace winswTests.Configuration
|
||||||
[TestFixture]
|
[TestFixture]
|
||||||
class ExamplesTest
|
class ExamplesTest
|
||||||
{
|
{
|
||||||
|
|
||||||
[Test]
|
[Test]
|
||||||
public void allOptionsConfigShouldDeclareDefaults()
|
public void AllOptionsConfigShouldDeclareDefaults()
|
||||||
{
|
{
|
||||||
ServiceDescriptor d = doLoad("allOptions");
|
ServiceDescriptor d = DoLoad("allOptions");
|
||||||
|
|
||||||
Assert.AreEqual("myapp", d.Id);
|
Assert.AreEqual("myapp", d.Id);
|
||||||
Assert.AreEqual("MyApp Service (powered by WinSW)", d.Caption);
|
Assert.AreEqual("MyApp Service (powered by WinSW)", d.Caption);
|
||||||
|
@ -31,9 +27,9 @@ namespace winswTests.Configuration
|
||||||
}
|
}
|
||||||
|
|
||||||
[Test]
|
[Test]
|
||||||
public void minimalConfigShouldDeclareDefaults()
|
public void MinimalConfigShouldDeclareDefaults()
|
||||||
{
|
{
|
||||||
ServiceDescriptor d = doLoad("minimal");
|
ServiceDescriptor d = DoLoad("minimal");
|
||||||
|
|
||||||
Assert.AreEqual("myapp", d.Id);
|
Assert.AreEqual("myapp", d.Id);
|
||||||
Assert.AreEqual("MyApp Service (powered by WinSW)", d.Caption);
|
Assert.AreEqual("MyApp Service (powered by WinSW)", d.Caption);
|
||||||
|
@ -43,13 +39,15 @@ namespace winswTests.Configuration
|
||||||
ServiceDescriptorAssert.AssertAllOptionalPropertiesAreDefault(d);
|
ServiceDescriptorAssert.AssertAllOptionalPropertiesAreDefault(d);
|
||||||
}
|
}
|
||||||
|
|
||||||
private ServiceDescriptor doLoad(string exampleName) {
|
private ServiceDescriptor DoLoad(string exampleName)
|
||||||
|
{
|
||||||
var dir = Directory.GetCurrentDirectory();
|
var dir = Directory.GetCurrentDirectory();
|
||||||
string path = Path.GetFullPath(dir + "\\..\\..\\..\\..\\..\\..\\examples\\sample-" + exampleName + ".xml");
|
string path = Path.GetFullPath(dir + "\\..\\..\\..\\..\\..\\..\\examples\\sample-" + exampleName + ".xml");
|
||||||
if (!File.Exists(path))
|
if (!File.Exists(path))
|
||||||
{
|
{
|
||||||
throw new FileNotFoundException("Cannot find the XML file " + path, path);
|
throw new FileNotFoundException("Cannot find the XML file " + path, path);
|
||||||
}
|
}
|
||||||
|
|
||||||
XmlDocument dom = new XmlDocument();
|
XmlDocument dom = new XmlDocument();
|
||||||
dom.Load(path);
|
dom.Load(path);
|
||||||
return new ServiceDescriptor(dom);
|
return new ServiceDescriptor(dom);
|
||||||
|
|
|
@ -1,8 +1,6 @@
|
||||||
using NUnit.Framework;
|
using System;
|
||||||
using System;
|
|
||||||
using System.Collections.Generic;
|
|
||||||
using System.IO;
|
using System.IO;
|
||||||
using System.Text;
|
using NUnit.Framework;
|
||||||
using winsw;
|
using winsw;
|
||||||
using winswTests.Util;
|
using winswTests.Util;
|
||||||
|
|
||||||
|
@ -22,7 +20,7 @@ namespace winswTests
|
||||||
var sd = ConfigXmlBuilder.create()
|
var sd = ConfigXmlBuilder.create()
|
||||||
.WithDownload(d)
|
.WithDownload(d)
|
||||||
.ToServiceDescriptor(true);
|
.ToServiceDescriptor(true);
|
||||||
var loaded = getSingleEntry(sd);
|
var loaded = GetSingleEntry(sd);
|
||||||
|
|
||||||
// Check default values
|
// Check default values
|
||||||
Assert.That(loaded.FailOnError, Is.EqualTo(false));
|
Assert.That(loaded.FailOnError, Is.EqualTo(false));
|
||||||
|
@ -40,7 +38,7 @@ namespace winswTests
|
||||||
var sd = ConfigXmlBuilder.create()
|
var sd = ConfigXmlBuilder.create()
|
||||||
.WithDownload(d)
|
.WithDownload(d)
|
||||||
.ToServiceDescriptor(true);
|
.ToServiceDescriptor(true);
|
||||||
var loaded = getSingleEntry(sd);
|
var loaded = GetSingleEntry(sd);
|
||||||
|
|
||||||
// Check default values
|
// Check default values
|
||||||
Assert.That(loaded.FailOnError, Is.EqualTo(true));
|
Assert.That(loaded.FailOnError, Is.EqualTo(true));
|
||||||
|
@ -58,7 +56,7 @@ namespace winswTests
|
||||||
var sd = ConfigXmlBuilder.create()
|
var sd = ConfigXmlBuilder.create()
|
||||||
.WithDownload(d)
|
.WithDownload(d)
|
||||||
.ToServiceDescriptor(true);
|
.ToServiceDescriptor(true);
|
||||||
var loaded = getSingleEntry(sd);
|
var loaded = GetSingleEntry(sd);
|
||||||
|
|
||||||
// Check default values
|
// Check default values
|
||||||
Assert.That(loaded.FailOnError, Is.EqualTo(false));
|
Assert.That(loaded.FailOnError, Is.EqualTo(false));
|
||||||
|
@ -77,19 +75,19 @@ namespace winswTests
|
||||||
{
|
{
|
||||||
var d = new Download(protocolPrefix + "myServer.com:8080/file.txt", To,
|
var d = new Download(protocolPrefix + "myServer.com:8080/file.txt", To,
|
||||||
auth: Download.AuthType.basic, username: "aUser", password: "aPassword");
|
auth: Download.AuthType.basic, username: "aUser", password: "aPassword");
|
||||||
assertInitializationFails(d, "you're sending your credentials in clear text to the server");
|
AssertInitializationFails(d, "you're sending your credentials in clear text to the server");
|
||||||
}
|
}
|
||||||
|
|
||||||
public void ShouldRejectBasicAuth_without_username()
|
public void ShouldRejectBasicAuth_without_username()
|
||||||
{
|
{
|
||||||
var d = new Download(From, To, auth: Download.AuthType.basic, username: null, password: "aPassword");
|
var d = new Download(From, To, auth: Download.AuthType.basic, username: null, password: "aPassword");
|
||||||
assertInitializationFails(d, "Basic Auth is enabled, but username is not specified");
|
AssertInitializationFails(d, "Basic Auth is enabled, but username is not specified");
|
||||||
}
|
}
|
||||||
|
|
||||||
public void ShouldRejectBasicAuth_without_password()
|
public void ShouldRejectBasicAuth_without_password()
|
||||||
{
|
{
|
||||||
var d = new Download(From, To, auth: Download.AuthType.basic, username: "aUser", password: null);
|
var d = new Download(From, To, auth: Download.AuthType.basic, username: "aUser", password: null);
|
||||||
assertInitializationFails(d, "Basic Auth is enabled, but password is not specified");
|
AssertInitializationFails(d, "Basic Auth is enabled, but password is not specified");
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
|
@ -105,7 +103,7 @@ namespace winswTests
|
||||||
.WithDownload(d)
|
.WithDownload(d)
|
||||||
.ToServiceDescriptor(true);
|
.ToServiceDescriptor(true);
|
||||||
|
|
||||||
var loaded = getSingleEntry(sd);
|
var loaded = GetSingleEntry(sd);
|
||||||
Assert.That(loaded.From, Is.EqualTo(From));
|
Assert.That(loaded.From, Is.EqualTo(From));
|
||||||
Assert.That(loaded.To, Is.EqualTo(To));
|
Assert.That(loaded.To, Is.EqualTo(To));
|
||||||
Assert.That(loaded.FailOnError, Is.EqualTo(failOnError), "Unexpected FailOnError value");
|
Assert.That(loaded.FailOnError, Is.EqualTo(failOnError), "Unexpected FailOnError value");
|
||||||
|
@ -121,7 +119,7 @@ namespace winswTests
|
||||||
.WithRawEntry("<download from=\"http://www.nosuchhostexists.foo.myorg/foo.xml\" to=\"%BASE%\\foo.xml\"/>")
|
.WithRawEntry("<download from=\"http://www.nosuchhostexists.foo.myorg/foo.xml\" to=\"%BASE%\\foo.xml\"/>")
|
||||||
.ToServiceDescriptor(true);
|
.ToServiceDescriptor(true);
|
||||||
|
|
||||||
var loaded = getSingleEntry(sd);
|
var loaded = GetSingleEntry(sd);
|
||||||
Assert.That(loaded.FailOnError, Is.False);
|
Assert.That(loaded.FailOnError, Is.False);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -134,7 +132,7 @@ namespace winswTests
|
||||||
var sd = ConfigXmlBuilder.create()
|
var sd = ConfigXmlBuilder.create()
|
||||||
.WithRawEntry("<download from=\"http://www.nosuchhostexists.foo.myorg/foo.xml\" to=\"%BASE%\\foo.xml\" auth=\"" + authType + "\"/>")
|
.WithRawEntry("<download from=\"http://www.nosuchhostexists.foo.myorg/foo.xml\" to=\"%BASE%\\foo.xml\" auth=\"" + authType + "\"/>")
|
||||||
.ToServiceDescriptor(true);
|
.ToServiceDescriptor(true);
|
||||||
var loaded = getSingleEntry(sd);
|
var loaded = GetSingleEntry(sd);
|
||||||
Assert.That(loaded.Auth, Is.EqualTo(Download.AuthType.sspi));
|
Assert.That(loaded.Auth, Is.EqualTo(Download.AuthType.sspi));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -146,27 +144,28 @@ namespace winswTests
|
||||||
.WithRawEntry("<download from=\"http://www.nosuchhostexists.foo.myorg/foo.xml\" to=\"%BASE%\\foo.xml\" auth=\"digest\"/>")
|
.WithRawEntry("<download from=\"http://www.nosuchhostexists.foo.myorg/foo.xml\" to=\"%BASE%\\foo.xml\" auth=\"digest\"/>")
|
||||||
.ToServiceDescriptor(true);
|
.ToServiceDescriptor(true);
|
||||||
|
|
||||||
ExceptionHelper.assertFails("Cannot parse <auth> Enum value from string 'digest'", typeof(InvalidDataException), delegate {
|
ExceptionHelper.assertFails("Cannot parse <auth> Enum value from string 'digest'", typeof(InvalidDataException), () =>
|
||||||
var d = getSingleEntry(sd);
|
{
|
||||||
|
var d = GetSingleEntry(sd);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
private Download getSingleEntry(ServiceDescriptor sd)
|
private Download GetSingleEntry(ServiceDescriptor sd)
|
||||||
{
|
{
|
||||||
var downloads = sd.Downloads.ToArray();
|
var downloads = sd.Downloads.ToArray();
|
||||||
Assert.That(downloads.Length, Is.EqualTo(1), "Service Descriptor is expected to have only one entry");
|
Assert.That(downloads.Length, Is.EqualTo(1), "Service Descriptor is expected to have only one entry");
|
||||||
return downloads[0];
|
return downloads[0];
|
||||||
}
|
}
|
||||||
|
|
||||||
private void assertInitializationFails(Download download, String expectedMessagePart = null, Type expectedExceptionType = null)
|
private void AssertInitializationFails(Download download, String expectedMessagePart = null, Type expectedExceptionType = null)
|
||||||
{
|
{
|
||||||
var sd = ConfigXmlBuilder.create()
|
var sd = ConfigXmlBuilder.create()
|
||||||
.WithDownload(download)
|
.WithDownload(download)
|
||||||
.ToServiceDescriptor(true);
|
.ToServiceDescriptor(true);
|
||||||
|
|
||||||
ExceptionHelper.assertFails(expectedMessagePart, expectedExceptionType ?? typeof(InvalidDataException), delegate
|
ExceptionHelper.assertFails(expectedMessagePart, expectedExceptionType ?? typeof(InvalidDataException), () =>
|
||||||
{
|
{
|
||||||
var d = getSingleEntry(sd);
|
var d = GetSingleEntry(sd);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,6 +1,4 @@
|
||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
|
||||||
using System.Text;
|
|
||||||
|
|
||||||
namespace winswTests.Extensions
|
namespace winswTests.Extensions
|
||||||
{
|
{
|
||||||
|
@ -15,7 +13,7 @@ namespace winswTests.Extensions
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="type">Type of the extension</param>
|
/// <param name="type">Type of the extension</param>
|
||||||
/// <returns>String for Type locator, which includes class and assembly names</returns>
|
/// <returns>String for Type locator, which includes class and assembly names</returns>
|
||||||
public static String getExtensionClassNameWithAssembly(Type type)
|
public static String GetExtensionClassNameWithAssembly(Type type)
|
||||||
{
|
{
|
||||||
return type.ToString() + ", " + type.Assembly;
|
return type.ToString() + ", " + type.Assembly;
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,14 +1,13 @@
|
||||||
using winsw;
|
using System;
|
||||||
using NUnit.Framework;
|
|
||||||
using winsw.Extensions;
|
|
||||||
using winsw.Plugins.SharedDirectoryMapper;
|
|
||||||
using winsw.Plugins.RunawayProcessKiller;
|
|
||||||
using winswTests.Util;
|
|
||||||
using System.IO;
|
|
||||||
using System.Diagnostics;
|
|
||||||
using winsw.Util;
|
|
||||||
using System;
|
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
|
using System.Diagnostics;
|
||||||
|
using System.IO;
|
||||||
|
using NUnit.Framework;
|
||||||
|
using winsw;
|
||||||
|
using winsw.Extensions;
|
||||||
|
using winsw.Plugins.RunawayProcessKiller;
|
||||||
|
using winsw.Util;
|
||||||
|
using winswTests.Util;
|
||||||
|
|
||||||
namespace winswTests.Extensions
|
namespace winswTests.Extensions
|
||||||
{
|
{
|
||||||
|
@ -17,7 +16,7 @@ namespace winswTests.Extensions
|
||||||
{
|
{
|
||||||
ServiceDescriptor _testServiceDescriptor;
|
ServiceDescriptor _testServiceDescriptor;
|
||||||
|
|
||||||
string testExtension = getExtensionClassNameWithAssembly(typeof(RunawayProcessKillerExtension));
|
string testExtension = GetExtensionClassNameWithAssembly(typeof(RunawayProcessKillerExtension));
|
||||||
|
|
||||||
[SetUp]
|
[SetUp]
|
||||||
public void SetUp()
|
public void SetUp()
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
using winsw;
|
using NUnit.Framework;
|
||||||
using NUnit.Framework;
|
using winsw;
|
||||||
using winsw.Extensions;
|
using winsw.Extensions;
|
||||||
using winsw.Plugins.SharedDirectoryMapper;
|
using winsw.Plugins.SharedDirectoryMapper;
|
||||||
|
|
||||||
|
@ -10,12 +10,11 @@ namespace winswTests.Extensions
|
||||||
{
|
{
|
||||||
ServiceDescriptor _testServiceDescriptor;
|
ServiceDescriptor _testServiceDescriptor;
|
||||||
|
|
||||||
string testExtension = getExtensionClassNameWithAssembly(typeof(SharedDirectoryMapper));
|
string testExtension = GetExtensionClassNameWithAssembly(typeof(SharedDirectoryMapper));
|
||||||
|
|
||||||
[SetUp]
|
[SetUp]
|
||||||
public void SetUp()
|
public void SetUp()
|
||||||
{
|
{
|
||||||
|
|
||||||
string seedXml = "<?xml version=\"1.0\" encoding=\"utf-8\" ?>"
|
string seedXml = "<?xml version=\"1.0\" encoding=\"utf-8\" ?>"
|
||||||
+ "<service> "
|
+ "<service> "
|
||||||
+ " <id>SERVICE_NAME</id> "
|
+ " <id>SERVICE_NAME</id> "
|
||||||
|
|
|
@ -7,7 +7,6 @@ namespace winswTests
|
||||||
[TestFixture]
|
[TestFixture]
|
||||||
class MainTest
|
class MainTest
|
||||||
{
|
{
|
||||||
|
|
||||||
[Test]
|
[Test]
|
||||||
public void PrintVersion()
|
public void PrintVersion()
|
||||||
{
|
{
|
||||||
|
@ -26,7 +25,7 @@ namespace winswTests
|
||||||
StringAssert.Contains("start", cliOut, "Expected that help refers start command");
|
StringAssert.Contains("start", cliOut, "Expected that help refers start command");
|
||||||
StringAssert.Contains("help", cliOut, "Expected that help refers help command");
|
StringAssert.Contains("help", cliOut, "Expected that help refers help command");
|
||||||
StringAssert.Contains("version", cliOut, "Expected that help refers version command");
|
StringAssert.Contains("version", cliOut, "Expected that help refers version command");
|
||||||
//TODO: check all commands after the migration of ccommands to enum
|
// TODO: check all commands after the migration of ccommands to enum
|
||||||
|
|
||||||
// Extra options
|
// Extra options
|
||||||
StringAssert.Contains("/redirect", cliOut, "Expected that help message refers the redirect message");
|
StringAssert.Contains("/redirect", cliOut, "Expected that help message refers the redirect message");
|
||||||
|
@ -37,7 +36,7 @@ namespace winswTests
|
||||||
{
|
{
|
||||||
const string commandName = "nonExistentCommand";
|
const string commandName = "nonExistentCommand";
|
||||||
string expectedMessage = "Unknown command: " + commandName.ToLower();
|
string expectedMessage = "Unknown command: " + commandName.ToLower();
|
||||||
CLITestResult res = CLITestHelper.CLIErrorTest(new[] {commandName});
|
CLITestResult res = CLITestHelper.CLIErrorTest(new[] { commandName });
|
||||||
|
|
||||||
Assert.True(res.HasException, "Expected an exception due to the wrong command");
|
Assert.True(res.HasException, "Expected an exception due to the wrong command");
|
||||||
StringAssert.Contains(expectedMessage, res.Out, "Expected the message about unknown command");
|
StringAssert.Contains(expectedMessage, res.Out, "Expected the message about unknown command");
|
||||||
|
|
|
@ -1,18 +1,16 @@
|
||||||
using System;
|
using System.Diagnostics;
|
||||||
using System.Diagnostics;
|
|
||||||
using NUnit.Framework;
|
using NUnit.Framework;
|
||||||
using winsw;
|
using winsw;
|
||||||
|
|
||||||
namespace winswTests
|
namespace winswTests
|
||||||
{
|
{
|
||||||
using System;
|
using System;
|
||||||
using WMI;
|
|
||||||
using winswTests.Util;
|
using winswTests.Util;
|
||||||
|
using WMI;
|
||||||
|
|
||||||
[TestFixture]
|
[TestFixture]
|
||||||
public class ServiceDescriptorTests
|
public class ServiceDescriptorTests
|
||||||
{
|
{
|
||||||
|
|
||||||
private ServiceDescriptor _extendedServiceDescriptor;
|
private ServiceDescriptor _extendedServiceDescriptor;
|
||||||
|
|
||||||
private const string ExpectedWorkingDirectory = @"Z:\Path\SubPath";
|
private const string ExpectedWorkingDirectory = @"Z:\Path\SubPath";
|
||||||
|
@ -52,7 +50,7 @@ namespace winswTests
|
||||||
}
|
}
|
||||||
|
|
||||||
[Test]
|
[Test]
|
||||||
[ExpectedException(typeof(System.ArgumentException))]
|
[ExpectedException(typeof(ArgumentException))]
|
||||||
public void IncorrectStartMode()
|
public void IncorrectStartMode()
|
||||||
{
|
{
|
||||||
const string SeedXml = "<service>"
|
const string SeedXml = "<service>"
|
||||||
|
@ -105,6 +103,7 @@ namespace winswTests
|
||||||
_extendedServiceDescriptor = ServiceDescriptor.FromXML(SeedXml);
|
_extendedServiceDescriptor = ServiceDescriptor.FromXML(SeedXml);
|
||||||
Assert.That(_extendedServiceDescriptor.StartMode, Is.EqualTo(StartMode.Manual));
|
Assert.That(_extendedServiceDescriptor.StartMode, Is.EqualTo(StartMode.Manual));
|
||||||
}
|
}
|
||||||
|
|
||||||
[Test]
|
[Test]
|
||||||
public void VerifyWorkingDirectory()
|
public void VerifyWorkingDirectory()
|
||||||
{
|
{
|
||||||
|
@ -298,13 +297,13 @@ namespace winswTests
|
||||||
Assert.NotNull(logHandler);
|
Assert.NotNull(logHandler);
|
||||||
Assert.That(logHandler.SizeTheshold, Is.EqualTo(10240 * 1024));
|
Assert.That(logHandler.SizeTheshold, Is.EqualTo(10240 * 1024));
|
||||||
Assert.That(logHandler.FilePattern, Is.EqualTo("yyyy-MM-dd"));
|
Assert.That(logHandler.FilePattern, Is.EqualTo("yyyy-MM-dd"));
|
||||||
Assert.That(logHandler.AutoRollAtTime, Is.EqualTo((TimeSpan?)new TimeSpan(0,0,0)));
|
Assert.That(logHandler.AutoRollAtTime, Is.EqualTo((TimeSpan?)new TimeSpan(0, 0, 0)));
|
||||||
}
|
}
|
||||||
|
|
||||||
[Test]
|
[Test]
|
||||||
public void VerifyServiceLogonRightGraceful()
|
public void VerifyServiceLogonRightGraceful()
|
||||||
{
|
{
|
||||||
const string seedXml="<service>"
|
const string seedXml = "<service>"
|
||||||
+ "<serviceaccount>"
|
+ "<serviceaccount>"
|
||||||
+ "<domain>" + Domain + "</domain>"
|
+ "<domain>" + Domain + "</domain>"
|
||||||
+ "<user>" + Username + "</user>"
|
+ "<user>" + Username + "</user>"
|
||||||
|
@ -315,6 +314,7 @@ namespace winswTests
|
||||||
var serviceDescriptor = ServiceDescriptor.FromXML(seedXml);
|
var serviceDescriptor = ServiceDescriptor.FromXML(seedXml);
|
||||||
Assert.That(serviceDescriptor.AllowServiceAcountLogonRight, Is.EqualTo(false));
|
Assert.That(serviceDescriptor.AllowServiceAcountLogonRight, Is.EqualTo(false));
|
||||||
}
|
}
|
||||||
|
|
||||||
[Test]
|
[Test]
|
||||||
public void VerifyServiceLogonRightOmitted()
|
public void VerifyServiceLogonRightOmitted()
|
||||||
{
|
{
|
||||||
|
@ -438,9 +438,11 @@ namespace winswTests
|
||||||
public void DelayedStart_RoundTrip(bool enabled)
|
public void DelayedStart_RoundTrip(bool enabled)
|
||||||
{
|
{
|
||||||
var bldr = ConfigXmlBuilder.create();
|
var bldr = ConfigXmlBuilder.create();
|
||||||
if (enabled) {
|
if (enabled)
|
||||||
|
{
|
||||||
bldr = bldr.WithDelayedAutoStart();
|
bldr = bldr.WithDelayedAutoStart();
|
||||||
}
|
}
|
||||||
|
|
||||||
var sd = bldr.ToServiceDescriptor();
|
var sd = bldr.ToServiceDescriptor();
|
||||||
Assert.That(sd.DelayedAutoStart, Is.EqualTo(enabled));
|
Assert.That(sd.DelayedAutoStart, Is.EqualTo(enabled));
|
||||||
}
|
}
|
||||||
|
|
|
@ -22,6 +22,7 @@ namespace winswTests.Util
|
||||||
+ "</workingdirectory>"
|
+ "</workingdirectory>"
|
||||||
+ @"<logpath>C:\winsw\logs</logpath>"
|
+ @"<logpath>C:\winsw\logs</logpath>"
|
||||||
+ "</service>";
|
+ "</service>";
|
||||||
|
|
||||||
private static readonly ServiceDescriptor DefaultServiceDescriptor = ServiceDescriptor.FromXML(SeedXml);
|
private static readonly ServiceDescriptor DefaultServiceDescriptor = ServiceDescriptor.FromXML(SeedXml);
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
|
@ -61,6 +62,7 @@ namespace winswTests.Util
|
||||||
|
|
||||||
using (swOut = new StringWriter())
|
using (swOut = new StringWriter())
|
||||||
using (swErr = new StringWriter())
|
using (swErr = new StringWriter())
|
||||||
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
Console.SetOut(swOut);
|
Console.SetOut(swOut);
|
||||||
|
@ -85,6 +87,7 @@ namespace winswTests.Util
|
||||||
Console.WriteLine(testEx);
|
Console.WriteLine(testEx);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return new CLITestResult(swOut.ToString(), swErr.ToString(), testEx);
|
return new CLITestResult(swOut.ToString(), swErr.ToString(), testEx);
|
||||||
}
|
}
|
||||||
|
@ -104,7 +107,7 @@ namespace winswTests.Util
|
||||||
[CanBeNull]
|
[CanBeNull]
|
||||||
public Exception Exception { get; private set; }
|
public Exception Exception { get; private set; }
|
||||||
|
|
||||||
public bool HasException { get { return Exception != null; } }
|
public bool HasException => Exception != null;
|
||||||
|
|
||||||
public CLITestResult(String output, String err, Exception exception = null)
|
public CLITestResult(String output, String err, Exception exception = null)
|
||||||
{
|
{
|
||||||
|
|
|
@ -53,10 +53,12 @@ namespace winswTests.Util
|
||||||
// TODO: The encoding is generally wrong
|
// TODO: The encoding is generally wrong
|
||||||
str.Append("<?xml version=\"1.0\" encoding=\"utf-8\"?>\n");
|
str.Append("<?xml version=\"1.0\" encoding=\"utf-8\"?>\n");
|
||||||
}
|
}
|
||||||
|
|
||||||
if (XMLComment != null)
|
if (XMLComment != null)
|
||||||
{
|
{
|
||||||
str.AppendFormat("<!--{0}-->\n", XMLComment);
|
str.AppendFormat("<!--{0}-->\n", XMLComment);
|
||||||
}
|
}
|
||||||
|
|
||||||
str.Append("<service>\n");
|
str.Append("<service>\n");
|
||||||
str.AppendFormat(" <id>{0}</id>\n", Id);
|
str.AppendFormat(" <id>{0}</id>\n", Id);
|
||||||
str.AppendFormat(" <name>{0}</name>\n", Name);
|
str.AppendFormat(" <name>{0}</name>\n", Name);
|
||||||
|
@ -76,6 +78,7 @@ namespace winswTests.Util
|
||||||
{
|
{
|
||||||
str.Append(xml);
|
str.Append(xml);
|
||||||
}
|
}
|
||||||
|
|
||||||
str.Append(" </extensions>\n");
|
str.Append(" </extensions>\n");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -86,6 +89,7 @@ namespace winswTests.Util
|
||||||
Console.Out.WriteLine("Produced config:");
|
Console.Out.WriteLine("Produced config:");
|
||||||
Console.Out.WriteLine(res);
|
Console.Out.WriteLine(res);
|
||||||
}
|
}
|
||||||
|
|
||||||
return res;
|
return res;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -107,14 +111,14 @@ namespace winswTests.Util
|
||||||
|
|
||||||
public ConfigXmlBuilder WithRunawayProcessKiller(RunawayProcessKillerExtension ext, string extensionId = "killRunawayProcess", bool enabled = true)
|
public ConfigXmlBuilder WithRunawayProcessKiller(RunawayProcessKillerExtension ext, string extensionId = "killRunawayProcess", bool enabled = true)
|
||||||
{
|
{
|
||||||
var fullyQualifiedExtensionName = ExtensionTestBase.getExtensionClassNameWithAssembly(typeof(RunawayProcessKillerExtension));
|
var fullyQualifiedExtensionName = ExtensionTestBase.GetExtensionClassNameWithAssembly(typeof(RunawayProcessKillerExtension));
|
||||||
StringBuilder str = new StringBuilder();
|
StringBuilder str = new StringBuilder();
|
||||||
str.AppendFormat(" <extension enabled=\"{0}\" className=\"{1}\" id=\"{2}\">\n", new Object[] { enabled, fullyQualifiedExtensionName, extensionId});
|
str.AppendFormat(" <extension enabled=\"{0}\" className=\"{1}\" id=\"{2}\">\n", new Object[] { enabled, fullyQualifiedExtensionName, extensionId });
|
||||||
str.AppendFormat(" <pidfile>{0}</pidfile>\n", ext.Pidfile);
|
str.AppendFormat(" <pidfile>{0}</pidfile>\n", ext.Pidfile);
|
||||||
str.AppendFormat(" <stopTimeout>{0}</stopTimeout>\n", ext.StopTimeout.TotalMilliseconds);
|
str.AppendFormat(" <stopTimeout>{0}</stopTimeout>\n", ext.StopTimeout.TotalMilliseconds);
|
||||||
str.AppendFormat(" <stopParentFirst>{0}</stopParentFirst>\n", ext.StopParentProcessFirst);
|
str.AppendFormat(" <stopParentFirst>{0}</stopParentFirst>\n", ext.StopParentProcessFirst);
|
||||||
str.AppendFormat(" <checkWinSWEnvironmentVariable>{0}</checkWinSWEnvironmentVariable>\n", ext.CheckWinSWEnvironmentVariable);
|
str.AppendFormat(" <checkWinSWEnvironmentVariable>{0}</checkWinSWEnvironmentVariable>\n", ext.CheckWinSWEnvironmentVariable);
|
||||||
str.Append( " </extension>\n");
|
str.Append(" </extension>\n");
|
||||||
ExtensionXmls.Add(str.ToString());
|
ExtensionXmls.Add(str.ToString());
|
||||||
|
|
||||||
return this;
|
return this;
|
||||||
|
@ -123,7 +127,7 @@ namespace winswTests.Util
|
||||||
public ConfigXmlBuilder WithDownload(Download download)
|
public ConfigXmlBuilder WithDownload(Download download)
|
||||||
{
|
{
|
||||||
StringBuilder str = new StringBuilder();
|
StringBuilder str = new StringBuilder();
|
||||||
str.AppendFormat("<download from=\"{0}\" to=\"{1}\" failOnError=\"{2}\"", new Object[] { download.From, download.To, download.FailOnError});
|
str.AppendFormat("<download from=\"{0}\" to=\"{1}\" failOnError=\"{2}\"", new Object[] { download.From, download.To, download.FailOnError });
|
||||||
|
|
||||||
// Authentication
|
// Authentication
|
||||||
if (download.Auth != Download.AuthType.none)
|
if (download.Auth != Download.AuthType.none)
|
||||||
|
|
|
@ -1,7 +1,5 @@
|
||||||
using NUnit.Framework;
|
using System;
|
||||||
using System;
|
using NUnit.Framework;
|
||||||
using System.Collections.Generic;
|
|
||||||
using System.Text;
|
|
||||||
|
|
||||||
namespace winswTests.Util
|
namespace winswTests.Util
|
||||||
{
|
{
|
||||||
|
@ -28,8 +26,6 @@ namespace winswTests.Util
|
||||||
|
|
||||||
Assert.Fail("Expected exception " + expectedExceptionType + " to be thrown by the operation");
|
Assert.Fail("Expected exception " + expectedExceptionType + " to be thrown by the operation");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public delegate void ExceptionHelperExecutionBody();
|
public delegate void ExceptionHelperExecutionBody();
|
||||||
|
|
|
@ -1,8 +1,7 @@
|
||||||
using NUnit.Framework;
|
using System;
|
||||||
using System;
|
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.IO;
|
using System.IO;
|
||||||
using System.Text;
|
using NUnit.Framework;
|
||||||
|
|
||||||
namespace winswTests.Util
|
namespace winswTests.Util
|
||||||
{
|
{
|
||||||
|
@ -14,7 +13,7 @@ namespace winswTests.Util
|
||||||
/// <returns>tmp Dir</returns>
|
/// <returns>tmp Dir</returns>
|
||||||
public static string CreateTmpDirectory(String testName = null)
|
public static string CreateTmpDirectory(String testName = null)
|
||||||
{
|
{
|
||||||
string tempDirectory = Path.Combine(Path.GetTempPath(), "winswTests_" + (testName ?? "") + Path.GetRandomFileName());
|
string tempDirectory = Path.Combine(Path.GetTempPath(), "winswTests_" + (testName ?? string.Empty) + Path.GetRandomFileName());
|
||||||
Directory.CreateDirectory(tempDirectory);
|
Directory.CreateDirectory(tempDirectory);
|
||||||
Console.Out.WriteLine("Created the temporary directory: {0}", tempDirectory);
|
Console.Out.WriteLine("Created the temporary directory: {0}", tempDirectory);
|
||||||
return tempDirectory;
|
return tempDirectory;
|
||||||
|
@ -29,7 +28,8 @@ namespace winswTests.Util
|
||||||
{
|
{
|
||||||
Dictionary<string, string> res = new Dictionary<string, string>();
|
Dictionary<string, string> res = new Dictionary<string, string>();
|
||||||
var lines = File.ReadAllLines(filePath);
|
var lines = File.ReadAllLines(filePath);
|
||||||
foreach(var line in lines) {
|
foreach (var line in lines)
|
||||||
|
{
|
||||||
var parsed = line.Split("=".ToCharArray(), 2);
|
var parsed = line.Split("=".ToCharArray(), 2);
|
||||||
if (parsed.Length == 2)
|
if (parsed.Length == 2)
|
||||||
{
|
{
|
||||||
|
@ -40,6 +40,7 @@ namespace winswTests.Util
|
||||||
Assert.Fail("Wrong line in the parsed Set output file: " + line);
|
Assert.Fail("Wrong line in the parsed Set output file: " + line);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return res;
|
return res;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,14 +1,12 @@
|
||||||
using System;
|
using System;
|
||||||
using System.Diagnostics;
|
|
||||||
using NUnit.Framework;
|
|
||||||
using winsw;
|
|
||||||
using System.IO;
|
|
||||||
using winsw.Util;
|
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
|
using System.Diagnostics;
|
||||||
|
using System.IO;
|
||||||
|
using NUnit.Framework;
|
||||||
|
using winsw.Util;
|
||||||
|
|
||||||
namespace winswTests.Util
|
namespace winswTests.Util
|
||||||
{
|
{
|
||||||
|
|
||||||
[TestFixture]
|
[TestFixture]
|
||||||
class ProcessHelperTest
|
class ProcessHelperTest
|
||||||
{
|
{
|
||||||
|
@ -25,7 +23,6 @@ namespace winswTests.Util
|
||||||
String scriptFile = Path.Combine(tmpDir, "printenv.bat");
|
String scriptFile = Path.Combine(tmpDir, "printenv.bat");
|
||||||
File.WriteAllText(scriptFile, "set > " + envFile);
|
File.WriteAllText(scriptFile, "set > " + envFile);
|
||||||
|
|
||||||
|
|
||||||
Process proc = new Process();
|
Process proc = new Process();
|
||||||
var ps = proc.StartInfo;
|
var ps = proc.StartInfo;
|
||||||
ps.FileName = scriptFile;
|
ps.FileName = scriptFile;
|
||||||
|
@ -54,7 +51,7 @@ namespace winswTests.Util
|
||||||
{
|
{
|
||||||
var tmpDir = FilesystemTestHelper.CreateTmpDirectory();
|
var tmpDir = FilesystemTestHelper.CreateTmpDirectory();
|
||||||
String scriptFile = Path.Combine(tmpDir, "print_lots_to_stdout.bat");
|
String scriptFile = Path.Combine(tmpDir, "print_lots_to_stdout.bat");
|
||||||
var lotsOfStdOut = string.Join("", _Range(1,1000));
|
var lotsOfStdOut = string.Join(string.Empty, _Range(1, 1000));
|
||||||
File.WriteAllText(scriptFile, string.Format("echo \"{0}\"", lotsOfStdOut));
|
File.WriteAllText(scriptFile, string.Format("echo \"{0}\"", lotsOfStdOut));
|
||||||
|
|
||||||
Process proc = new Process();
|
Process proc = new Process();
|
||||||
|
@ -72,10 +69,11 @@ namespace winswTests.Util
|
||||||
private string[] _Range(int start, int limit)
|
private string[] _Range(int start, int limit)
|
||||||
{
|
{
|
||||||
var range = new List<string>();
|
var range = new List<string>();
|
||||||
for(var i = start; i<limit; i++)
|
for (var i = start; i < limit; i++)
|
||||||
{
|
{
|
||||||
range.Add(i.ToString());
|
range.Add(i.ToString());
|
||||||
}
|
}
|
||||||
|
|
||||||
return range.ToArray();
|
return range.ToArray();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,8 +1,6 @@
|
||||||
using NUnit.Framework;
|
using System.Collections.Generic;
|
||||||
using System;
|
|
||||||
using System.Collections.Generic;
|
|
||||||
using System.Reflection;
|
using System.Reflection;
|
||||||
using System.Text;
|
using NUnit.Framework;
|
||||||
using winsw;
|
using winsw;
|
||||||
using winsw.Configuration;
|
using winsw.Configuration;
|
||||||
|
|
||||||
|
@ -37,14 +35,17 @@ namespace winswTests.Util
|
||||||
AssertPropertyIsDefault(d, AllOptionalProperties);
|
AssertPropertyIsDefault(d, AllOptionalProperties);
|
||||||
}
|
}
|
||||||
|
|
||||||
private static List<string> AllProperties {
|
private static List<string> AllProperties
|
||||||
get {
|
{
|
||||||
|
get
|
||||||
|
{
|
||||||
var res = new List<string>();
|
var res = new List<string>();
|
||||||
var properties = typeof(IWinSWConfiguration).GetProperties();
|
var properties = typeof(IWinSWConfiguration).GetProperties();
|
||||||
foreach (var prop in properties)
|
foreach (var prop in properties)
|
||||||
{
|
{
|
||||||
res.Add(prop.Name);
|
res.Add(prop.Name);
|
||||||
}
|
}
|
||||||
|
|
||||||
return res;
|
return res;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -62,6 +63,4 @@ namespace winswTests.Util
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue