893 lines
32 KiB
C#
893 lines
32 KiB
C#
///////////////////////////////////////////////////////////////////////////////
|
|
//
|
|
// Microsoft Research Singularity
|
|
//
|
|
// Copyright (c) Microsoft Corporation. All rights reserved.
|
|
//
|
|
// Note: Service Manager client program
|
|
//
|
|
using System;
|
|
using System.Threading;
|
|
|
|
using Microsoft.SingSharp;
|
|
using Microsoft.SingSharp.Reflection;
|
|
using Microsoft.Singularity;
|
|
using Microsoft.Singularity.Applications;
|
|
using Microsoft.Singularity.Channels;
|
|
using Microsoft.Singularity.Configuration;
|
|
using Microsoft.Singularity.Contracts;
|
|
using Microsoft.Singularity.Directory;
|
|
using Microsoft.Singularity.Io;
|
|
using Microsoft.Singularity.ServiceManager;
|
|
[assembly: Transform(typeof(ApplicationResourceTransform))]
|
|
|
|
namespace Microsoft.Singularity.Applications.ServiceManager
|
|
{
|
|
[ConsoleCategory(HelpMessage="Service management client", DefaultAction=true)]
|
|
internal class DefaultConfig
|
|
{
|
|
[InputEndpoint("data")]
|
|
public readonly TRef<UnicodePipeContract.Exp:READY> Stdin;
|
|
|
|
[OutputEndpoint("data")]
|
|
public readonly TRef<UnicodePipeContract.Imp:READY> Stdout;
|
|
|
|
reflective internal DefaultConfig();
|
|
|
|
internal int AppMain()
|
|
{
|
|
Console.WriteLine("Use -? for help.");
|
|
return 0;
|
|
}
|
|
}
|
|
|
|
[ConsoleCategory(Action="start", HelpMessage="Start a service")]
|
|
internal class StartConfig
|
|
{
|
|
[InputEndpoint("data")]
|
|
public readonly TRef<UnicodePipeContract.Exp:READY> Stdin;
|
|
|
|
[OutputEndpoint("data")]
|
|
public readonly TRef<UnicodePipeContract.Imp:READY> Stdout;
|
|
|
|
[StringParameter("service", Mandatory=true, Position=0)]
|
|
internal string serviceName;
|
|
|
|
// [BoolParameter("w", Mandatory=false, HelpMessage="Wait for service to start.")]
|
|
public bool wait;
|
|
|
|
reflective internal StartConfig();
|
|
|
|
internal int AppMain()
|
|
{
|
|
return SMSClient.StartService((!)serviceName, wait);
|
|
}
|
|
}
|
|
|
|
[ConsoleCategory(Action="stop", HelpMessage="Stop a service")]
|
|
internal class StopServiceCommand
|
|
{
|
|
[InputEndpoint("data")]
|
|
public readonly TRef<UnicodePipeContract.Exp:READY> Stdin;
|
|
|
|
[OutputEndpoint("data")]
|
|
public readonly TRef<UnicodePipeContract.Imp:READY> Stdout;
|
|
|
|
[StringParameter("service", Mandatory=true, Position=0)]
|
|
internal string serviceName;
|
|
|
|
// [BoolParameter("w", Mandatory=false, HelpMessage="Wait for service to stop.")]
|
|
public bool wait;
|
|
|
|
reflective internal StopServiceCommand();
|
|
|
|
internal int AppMain()
|
|
{
|
|
return SMSClient.StopService((!)serviceName, wait);
|
|
}
|
|
}
|
|
|
|
[ConsoleCategory(Action="list", HelpMessage="Show a list of services")]
|
|
internal class ListConfig
|
|
{
|
|
[InputEndpoint("data")]
|
|
public readonly TRef<UnicodePipeContract.Exp:READY> Stdin;
|
|
|
|
[OutputEndpoint("data")]
|
|
public readonly TRef<UnicodePipeContract.Imp:READY> Stdout;
|
|
|
|
reflective internal ListConfig();
|
|
|
|
internal int AppMain()
|
|
{
|
|
return SMSClient.ListServices(this);
|
|
}
|
|
}
|
|
|
|
[ConsoleCategory(Action="show", HelpMessage="Show details about a specific service.")]
|
|
internal class ShowServiceParameters
|
|
{
|
|
[InputEndpoint("data")]
|
|
public readonly TRef<UnicodePipeContract.Exp:READY> Stdin;
|
|
|
|
[OutputEndpoint("data")]
|
|
public readonly TRef<UnicodePipeContract.Imp:READY> Stdout;
|
|
|
|
[StringParameter("service", Position=0, Mandatory=true, HelpMessage="The service to examine.")]
|
|
public string ServiceName;
|
|
|
|
reflective internal ShowServiceParameters();
|
|
|
|
internal int AppMain()
|
|
{
|
|
if (ServiceName == null) {
|
|
Console.WriteLine("The 'service' parameter is required, but has not been provided.");
|
|
return -1;
|
|
}
|
|
|
|
ServiceManagerContract.Imp! svmanager = SMSClient.ConnectServiceManager();
|
|
try {
|
|
ServiceError error = SMSClient.SelectService(svmanager, this.ServiceName);
|
|
if (error != ServiceError.None)
|
|
return -1;
|
|
|
|
bool errors = false;
|
|
|
|
svmanager.SendQueryServiceConfig();
|
|
switch receive {
|
|
case svmanager.CurrentServiceConfig(config):
|
|
SMSClient.ShowConfigDetailed(config);
|
|
config.Dispose();
|
|
break;
|
|
|
|
case svmanager.RequestFailed(err):
|
|
if (err == ServiceError.ServiceNotFound) {
|
|
Console.WriteLine("There is no service with name '{0}'.", this.ServiceName);
|
|
return -1;
|
|
}
|
|
|
|
Console.WriteLine("Failed to query service configuration.");
|
|
SMSClient.ShowServiceError(err);
|
|
errors = true;
|
|
break;
|
|
|
|
case svmanager.ChannelClosed():
|
|
Console.WriteLine("The Service Manager closed its channel unexpectedly.");
|
|
return -1;
|
|
}
|
|
|
|
svmanager.SendQueryServiceStatus();
|
|
switch receive {
|
|
case svmanager.CurrentServiceStatus(status):
|
|
Console.WriteLine();
|
|
SMSClient.ShowStatusDetailed(status);
|
|
status.Dispose();
|
|
break;
|
|
|
|
case svmanager.RequestFailed(err):
|
|
Console.WriteLine("Failed to query service status.");
|
|
SMSClient.ShowServiceError(err);
|
|
errors = true;
|
|
break;
|
|
|
|
case svmanager.ChannelClosed():
|
|
Console.WriteLine("The Service Manager closed its channel unexpectedly.");
|
|
return -1;
|
|
}
|
|
|
|
if (errors)
|
|
return -1;
|
|
else
|
|
return 0;
|
|
|
|
}
|
|
finally {
|
|
delete svmanager;
|
|
}
|
|
}
|
|
}
|
|
|
|
[ConsoleCategory(Action="watch", HelpMessage="Watch the status of a service")]
|
|
internal class WatchConfig
|
|
{
|
|
[InputEndpoint("data")]
|
|
public readonly TRef<UnicodePipeContract.Exp:READY> Stdin;
|
|
|
|
[OutputEndpoint("data")]
|
|
public readonly TRef<UnicodePipeContract.Imp:READY> Stdout;
|
|
|
|
[StringParameter("service", Mandatory=true, Position=0)]
|
|
internal string serviceName;
|
|
|
|
reflective internal WatchConfig();
|
|
|
|
internal int AppMain()
|
|
{
|
|
return SMSClient.WatchService((!)serviceName);
|
|
}
|
|
}
|
|
|
|
[ConsoleCategory(Action="watchall", HelpMessage="Watch the status of the Service Manager")]
|
|
internal class WatchAllConfig
|
|
{
|
|
[InputEndpoint("data")]
|
|
public readonly TRef<UnicodePipeContract.Exp:READY> Stdin;
|
|
|
|
[OutputEndpoint("data")]
|
|
public readonly TRef<UnicodePipeContract.Imp:READY> Stdout;
|
|
|
|
#if false
|
|
[BoolParameter("c", Mandatory=false, HelpMessage="Watch all service configuration changes")]
|
|
public bool watchConfigChanges;
|
|
|
|
[BoolParameter("s", Mandatory=false, HelpMessage="Watch all service status changes")]
|
|
public bool watchStatusChanges;
|
|
#endif
|
|
|
|
reflective internal WatchAllConfig();
|
|
|
|
internal int AppMain()
|
|
{
|
|
#if false
|
|
ServiceManagerEventMask desiredEvents = 0;
|
|
|
|
if (watchConfigChanges)
|
|
desiredEvents |= ServiceManagerEventMask.AnyServiceConfig;
|
|
|
|
if (watchStatusChanges)
|
|
desiredEvents |= ServiceManagerEventMask.AnyServiceStatus;
|
|
|
|
if (desiredEvents == 0)
|
|
desiredEvents = ServiceManagerEventMask.AnyServiceConfig | ServiceManagerEventMask.AnyServiceStatus;
|
|
#else
|
|
ServiceManagerEventMask desiredEvents = ServiceManagerEventMask.AnyServiceConfig | ServiceManagerEventMask.AnyServiceStatus;
|
|
#endif
|
|
|
|
ServiceManagerContract.Imp! svmanager = SMSClient.ConnectServiceManager();
|
|
|
|
svmanager.SendWatchServiceManager(desiredEvents);
|
|
|
|
switch receive {
|
|
case svmanager.Ok():
|
|
break;
|
|
|
|
case svmanager.RequestFailed(error):
|
|
Console.WriteLine("The Service Manager rejected the subscription request.");
|
|
SMSClient.ShowServiceError(error);
|
|
delete svmanager;
|
|
return -1;
|
|
}
|
|
|
|
Console.WriteLine("Watching Service Manager...");
|
|
|
|
for (;;) {
|
|
Console.WriteLine("Sending WaitNextServiceManagerChange");
|
|
svmanager.SendWaitNextServiceManagerChange();
|
|
|
|
Console.WriteLine("switch-receive");
|
|
|
|
switch receive {
|
|
case svmanager.ServiceManagerChanged(events):
|
|
Console.WriteLine("Service Manager events fired: {0:x8}", ((uint)events));
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
[ConsoleCategory(Action="create", HelpMessage="Create a new service entry")]
|
|
internal class CreateServiceCommand
|
|
{
|
|
[InputEndpoint("data")]
|
|
public readonly TRef<UnicodePipeContract.Exp:READY> Stdin;
|
|
|
|
[OutputEndpoint("data")]
|
|
public readonly TRef<UnicodePipeContract.Imp:READY> Stdout;
|
|
|
|
[StringParameter("service", Mandatory=true, Position=0)]
|
|
internal string serviceName;
|
|
|
|
[StringParameter("exe", Mandatory=false, HelpMessage="Executable to use; if omitted, uses service name.")]
|
|
public string executableName;
|
|
|
|
[StringParameter("display", Mandatory=false, HelpMessage="Display name to use; if omitted, uses service name.")]
|
|
public string displayName;
|
|
|
|
[BoolParameter("disabled", Mandatory=false, HelpMessage="Create in a disabled state.")]
|
|
public bool isAdministrativelyDisabled;
|
|
|
|
reflective internal CreateServiceCommand();
|
|
|
|
internal int AppMain()
|
|
{
|
|
assert serviceName != null;
|
|
if (serviceName.Length == 0) {
|
|
Console.WriteLine("Invalid service name.");
|
|
return -1;
|
|
}
|
|
|
|
if (executableName == null || executableName.Length == 0)
|
|
executableName = serviceName;
|
|
|
|
if (displayName == null || displayName.Length == 0)
|
|
displayName = serviceName;
|
|
|
|
ServiceManagerContract.Imp! svmanager = SMSClient.ConnectServiceManager();
|
|
try {
|
|
|
|
ServiceConfig config = new ServiceConfig();
|
|
config.ServiceName = Bitter.FromString2(serviceName);
|
|
config.ExecutableName = Bitter.FromString2(executableName);
|
|
config.DisplayName = Bitter.FromString2(displayName);
|
|
config.IsAdministrativelyDisabled = isAdministrativelyDisabled;
|
|
config.MinProcesses = 0;
|
|
config.MaxProcesses = 1;
|
|
config.MaxClientsPerProcess = ServiceConfig.UnlimitedClientsPerProcess;
|
|
config.MaxProcessAgeInSeconds = ServiceConfig.UnlimitedProcessAge;
|
|
|
|
svmanager.SendCreateService(config);
|
|
|
|
switch receive {
|
|
case svmanager.Ok():
|
|
Console.WriteLine("Service was successfully created.");
|
|
return 0;
|
|
|
|
case svmanager.RequestFailed(error):
|
|
Console.WriteLine("Failed to create service.");
|
|
SMSClient.ShowServiceError(error);
|
|
return -1;
|
|
}
|
|
|
|
}
|
|
finally {
|
|
delete svmanager;
|
|
}
|
|
}
|
|
}
|
|
|
|
[ConsoleCategory(Action="delete", HelpMessage="Delete an existing service")]
|
|
internal class DeleteServiceCommand
|
|
{
|
|
[InputEndpoint("data")]
|
|
public readonly TRef<UnicodePipeContract.Exp:READY> Stdin;
|
|
|
|
[OutputEndpoint("data")]
|
|
public readonly TRef<UnicodePipeContract.Imp:READY> Stdout;
|
|
|
|
[StringParameter("service", Mandatory=true, Position=0)]
|
|
internal string serviceName;
|
|
|
|
reflective internal DeleteServiceCommand();
|
|
|
|
internal int AppMain()
|
|
{
|
|
assert serviceName != null;
|
|
if (serviceName.Length == 0) {
|
|
Console.WriteLine("Invalid service name.");
|
|
return -1;
|
|
}
|
|
|
|
ServiceManagerContract.Imp! svmanager = SMSClient.ConnectServiceManager();
|
|
try {
|
|
|
|
ServiceError error = SMSClient.SelectService(svmanager, serviceName);
|
|
if (error != ServiceError.None)
|
|
return -1;
|
|
|
|
svmanager.SendDeleteService();
|
|
|
|
switch receive {
|
|
case svmanager.Ok():
|
|
Console.WriteLine("Service was successfully deleted.");
|
|
return 0;
|
|
|
|
case svmanager.RequestFailed(err):
|
|
Console.WriteLine("Failed to delete service.");
|
|
SMSClient.ShowServiceError(err);
|
|
return -1;
|
|
}
|
|
|
|
}
|
|
finally {
|
|
delete svmanager;
|
|
}
|
|
}
|
|
}
|
|
|
|
[ConsoleCategory(Action="enable", HelpMessage="Enable a service")]
|
|
internal class EnableServiceCommand
|
|
{
|
|
[InputEndpoint("data")]
|
|
public readonly TRef<UnicodePipeContract.Exp:READY> Stdin;
|
|
|
|
[OutputEndpoint("data")]
|
|
public readonly TRef<UnicodePipeContract.Imp:READY> Stdout;
|
|
|
|
[StringParameter("service", Mandatory=true, Position=0)]
|
|
internal string serviceName;
|
|
|
|
reflective internal EnableServiceCommand();
|
|
|
|
internal int AppMain()
|
|
{
|
|
assert serviceName != null;
|
|
if (serviceName.Length == 0) {
|
|
Console.WriteLine("Invalid service name.");
|
|
return -1;
|
|
}
|
|
|
|
ServiceManagerContract.Imp! svmanager = SMSClient.ConnectServiceManager();
|
|
try {
|
|
|
|
ServiceError error = SMSClient.SelectService(svmanager, serviceName);
|
|
if (error != ServiceError.None)
|
|
return -1;
|
|
|
|
svmanager.SendEnableService(true);
|
|
|
|
switch receive {
|
|
case svmanager.Ok():
|
|
Console.WriteLine("Service was successfully enabled.");
|
|
return 0;
|
|
|
|
case svmanager.RequestFailed(err):
|
|
Console.WriteLine("Failed to enable service.");
|
|
SMSClient.ShowServiceError(err);
|
|
return -1;
|
|
}
|
|
|
|
}
|
|
finally {
|
|
delete svmanager;
|
|
}
|
|
}
|
|
}
|
|
|
|
[ConsoleCategory(Action="disable", HelpMessage="Disable a service")]
|
|
internal class DisableServiceCommand
|
|
{
|
|
[InputEndpoint("data")]
|
|
public readonly TRef<UnicodePipeContract.Exp:READY> Stdin;
|
|
|
|
[OutputEndpoint("data")]
|
|
public readonly TRef<UnicodePipeContract.Imp:READY> Stdout;
|
|
|
|
[StringParameter("service", Mandatory=true, Position=0)]
|
|
internal string serviceName;
|
|
|
|
reflective internal DisableServiceCommand();
|
|
|
|
internal int AppMain()
|
|
{
|
|
assert serviceName != null;
|
|
if (serviceName.Length == 0) {
|
|
Console.WriteLine("Invalid service name.");
|
|
return -1;
|
|
}
|
|
|
|
ServiceManagerContract.Imp! svmanager = SMSClient.ConnectServiceManager();
|
|
try {
|
|
|
|
ServiceError error = SMSClient.SelectService(svmanager, serviceName);
|
|
if (error != ServiceError.None)
|
|
return -1;
|
|
|
|
svmanager.SendEnableService(false);
|
|
|
|
switch receive {
|
|
case svmanager.Ok():
|
|
Console.WriteLine("Service was successfully disabled.");
|
|
return 0;
|
|
|
|
case svmanager.RequestFailed(err):
|
|
Console.WriteLine("Failed to disable service.");
|
|
SMSClient.ShowServiceError(err);
|
|
return -1;
|
|
}
|
|
|
|
}
|
|
finally {
|
|
delete svmanager;
|
|
}
|
|
}
|
|
}
|
|
|
|
[ConsoleCategory(Action="kill", HelpMessage="Terminate the process(es) of a service.")]
|
|
internal class TerminateServiceCommand
|
|
{
|
|
[InputEndpoint("data")]
|
|
public readonly TRef<UnicodePipeContract.Exp:READY> Stdin;
|
|
|
|
[OutputEndpoint("data")]
|
|
public readonly TRef<UnicodePipeContract.Imp:READY> Stdout;
|
|
|
|
[StringParameter("service", Mandatory=true, Position=0)]
|
|
internal string serviceName;
|
|
|
|
[LongParameter("pid", Mandatory=false, Position=1, Default=-1)]
|
|
internal long processId;
|
|
|
|
reflective internal TerminateServiceCommand();
|
|
|
|
internal int AppMain()
|
|
{
|
|
assert serviceName != null;
|
|
if (serviceName.Length == 0) {
|
|
Console.WriteLine("Invalid service name.");
|
|
return -1;
|
|
}
|
|
|
|
ServiceManagerContract.Imp! svmanager = SMSClient.ConnectServiceManager();
|
|
try {
|
|
|
|
ServiceError error = SMSClient.SelectService(svmanager, serviceName);
|
|
if (error != ServiceError.None)
|
|
return -1;
|
|
|
|
if (processId != -1)
|
|
svmanager.SendTerminateServiceProcess((int)processId);
|
|
else
|
|
svmanager.SendTerminateServiceAllProcesses();
|
|
|
|
switch receive {
|
|
case svmanager.Ok():
|
|
return 0;
|
|
|
|
case svmanager.RequestFailed(err):
|
|
SMSClient.ShowServiceError(err);
|
|
return -1;
|
|
}
|
|
|
|
}
|
|
finally {
|
|
delete svmanager;
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
public class SMSClient
|
|
{
|
|
internal static ServiceManagerContract.Imp! ConnectServiceManager()
|
|
{
|
|
using (ImpatientWatcher watcher = new ImpatientWatcher("ConnectServiceManager", "create channel", 250)) {
|
|
ErrorCode error;
|
|
ServiceManagerContract.Imp! manager_imp;
|
|
ServiceManagerContract.Exp! manager_exp;
|
|
ServiceManagerContract.NewChannel(out manager_imp, out manager_exp);
|
|
|
|
watcher.NextStep("NewClientEndpoint", 250);
|
|
|
|
DirectoryServiceContract.Imp! rootds = DirectoryService.NewClientEndpoint();
|
|
try {
|
|
watcher.NextStep("SdsUtils.Bind", 1000);
|
|
if (SdsUtils.Bind(ServiceManagerContract.ModuleName, rootds, manager_exp, out error)) {
|
|
watcher.NextStep("RecvSuccess", 250);
|
|
manager_imp.RecvSuccess();
|
|
return manager_imp;
|
|
}
|
|
else {
|
|
delete manager_imp;
|
|
Console.WriteLine("Failed to contact the Service Manager. Error: " + SdsUtils.ErrorCodeToString(error));
|
|
throw new Exception("Failed to connect to Service Manager.");
|
|
}
|
|
}
|
|
finally {
|
|
delete rootds;
|
|
}
|
|
}
|
|
}
|
|
|
|
internal static ServiceError SelectService(ServiceManagerContract.Imp! svmanager, string! serviceName)
|
|
{
|
|
svmanager.SendSelectService(Bitter.FromString2(serviceName));
|
|
switch receive {
|
|
case svmanager.Ok():
|
|
// Console.WriteLine("Successfully selected service '{0}'.", serviceName);
|
|
return ServiceError.None;
|
|
|
|
case svmanager.RequestFailed(error):
|
|
Console.WriteLine("Failed to select service '{0}'.", serviceName);
|
|
ShowServiceError(error);
|
|
return error;
|
|
|
|
case svmanager.ChannelClosed():
|
|
throw new Exception("Service Manager closed channel before responding.");
|
|
}
|
|
}
|
|
|
|
internal static void ShowServiceError(ServiceError error)
|
|
{
|
|
Console.WriteLine("ServiceError: " + ServiceEnums.ToString(error));
|
|
}
|
|
|
|
static internal int StartService(string! serviceName, bool wait)
|
|
{
|
|
ServiceManagerContract.Imp! svmanager = ConnectServiceManager();
|
|
|
|
try {
|
|
|
|
ServiceError error = SelectService(svmanager, serviceName);
|
|
if (error != ServiceError.None) {
|
|
return -1;
|
|
}
|
|
|
|
if (wait) {
|
|
svmanager.SendStartServiceWait();
|
|
|
|
for (;;) {
|
|
switch receive {
|
|
case svmanager.RequestFailed(err):
|
|
ShowServiceError(err);
|
|
return -1;
|
|
|
|
case svmanager.ServiceStarting():
|
|
Console.WriteLine("Service Manager accepted request to start service '{0}'.", serviceName);
|
|
return 0;
|
|
|
|
case timeout(TimeSpan.FromSeconds(10)):
|
|
Console.WriteLine("waiting...");
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
else {
|
|
svmanager.SendStartServiceNoWait();
|
|
|
|
switch receive {
|
|
case svmanager.RequestFailed(err):
|
|
ShowServiceError(err);
|
|
return -1;
|
|
|
|
case svmanager.ServiceStarting():
|
|
Console.WriteLine("Service Manager accepted request to start service '{0}'.", serviceName);
|
|
return 0;
|
|
}
|
|
}
|
|
}
|
|
finally {
|
|
delete svmanager;
|
|
}
|
|
}
|
|
|
|
internal static int StopService(string! serviceName, bool wait)
|
|
{
|
|
ServiceManagerContract.Imp! svmanager = ConnectServiceManager();
|
|
|
|
try {
|
|
|
|
ServiceError error = SelectService(svmanager, serviceName);
|
|
if (error != ServiceError.None)
|
|
return -1;
|
|
|
|
if (wait) {
|
|
svmanager.SendStopServiceWait();
|
|
|
|
for (;;) {
|
|
switch receive {
|
|
case svmanager.RequestFailed(err):
|
|
ShowServiceError(err);
|
|
if (err == ServiceError.CannotStopService) {
|
|
Console.WriteLine("If this service is an 'always active' service, then the stop command cannot be used.");
|
|
Console.WriteLine("Instead, use the 'disable' command.");
|
|
}
|
|
return -1;
|
|
|
|
case svmanager.ServiceStopping():
|
|
Console.WriteLine("Service Manager accepted request to stop service '{0}'.", serviceName);
|
|
return 0;
|
|
|
|
case timeout(TimeSpan.FromSeconds(10)):
|
|
Console.WriteLine("waiting...");
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
else {
|
|
svmanager.SendStopServiceNoWait();
|
|
|
|
switch receive {
|
|
case svmanager.RequestFailed(err):
|
|
ShowServiceError(err);
|
|
return -1;
|
|
|
|
case svmanager.ServiceStopping():
|
|
Console.WriteLine("Service Manager accepted request to stop service '{0}'.", serviceName);
|
|
return 0;
|
|
}
|
|
}
|
|
}
|
|
finally {
|
|
delete svmanager;
|
|
}
|
|
}
|
|
|
|
internal static int WatchService(string! serviceName)
|
|
{
|
|
ServiceManagerContract.Imp! svmanager = ConnectServiceManager();
|
|
|
|
try {
|
|
|
|
ServiceError error = SelectService(svmanager, serviceName);
|
|
if (error != ServiceError.None) {
|
|
return -1;
|
|
}
|
|
|
|
svmanager.SendWatchServiceStatus();
|
|
|
|
switch receive {
|
|
case svmanager.RequestFailed(err):
|
|
ShowServiceError(err);
|
|
return -1;
|
|
|
|
case svmanager.Ok():
|
|
Console.WriteLine("Service Manager accepted request to watch service '{0}'.", serviceName);
|
|
break;
|
|
}
|
|
|
|
for (;;) {
|
|
svmanager.SendWaitServiceChange();
|
|
|
|
switch receive {
|
|
case svmanager.ServiceStatusChanged(ServiceStatus status, bool missedChange):
|
|
Console.WriteLine("Status changed: ");
|
|
Console.WriteLine(" State: " + ServiceEnums.ToString(status.State));
|
|
if (missedChange) {
|
|
Console.WriteLine(" Note: At least one status change was missed.");
|
|
}
|
|
break;
|
|
|
|
case svmanager.RequestFailed(err):
|
|
Console.WriteLine("Request failed.");
|
|
ShowServiceError(err);
|
|
return -1;
|
|
|
|
case svmanager.ChannelClosed():
|
|
Console.WriteLine("Service Manager closed channel!");
|
|
return -1;
|
|
}
|
|
}
|
|
|
|
}
|
|
finally {
|
|
delete svmanager;
|
|
}
|
|
}
|
|
|
|
const string ListServiceFormat = "{0,-20} {1,-10} {2,-6} {3}";
|
|
|
|
internal static int ListServices(ListConfig! config)
|
|
{
|
|
ServiceManagerContract.Imp! svmanager = ConnectServiceManager();
|
|
|
|
|
|
try {
|
|
Console.WriteLine(ListServiceFormat, "Name", "State", "PID", "Display Name");
|
|
Console.WriteLine(ListServiceFormat,
|
|
new String('-', 20),
|
|
new String('-', 10),
|
|
new String('-', 6),
|
|
new String('-', 30));
|
|
|
|
ServiceInfo[]! in ExHeap first_entries = new[ExHeap] ServiceInfo[40];
|
|
svmanager.SendEnumerateServices(first_entries);
|
|
|
|
for (;;) {
|
|
switch receive {
|
|
case svmanager.EnumerationTerminated(entries, count):
|
|
ListServices(entries, count);
|
|
delete entries;
|
|
return 0;
|
|
|
|
case svmanager.NextServiceInfo(entries, count):
|
|
ListServices(entries, count);
|
|
svmanager.SendEnumerateServices(entries);
|
|
break;
|
|
|
|
case svmanager.ChannelClosed():
|
|
Console.WriteLine("Service Manager channel closed");
|
|
return -1;
|
|
|
|
}
|
|
}
|
|
}
|
|
finally {
|
|
delete svmanager;
|
|
}
|
|
}
|
|
|
|
static void ListServices(ServiceInfo[]! in ExHeap entries, int count)
|
|
{
|
|
for (int i = 0; i < count; i++) {
|
|
expose(entries[i])
|
|
{
|
|
string! serviceName = ToString(entries[i].Config.ServiceName);
|
|
string! displayName = ToString(entries[i].Config.DisplayName);
|
|
string! stateString = ServiceEnums.ToString(entries[i].Status.State);
|
|
string! processIdString = entries[i].Status.ProcessId != -1 ?
|
|
(!)entries[i].Status.ProcessId.ToString() : "";
|
|
Console.WriteLine(ListServiceFormat, serviceName, stateString, processIdString, displayName);
|
|
}
|
|
}
|
|
}
|
|
|
|
public static string! ToString(char[] in ExHeap str)
|
|
{
|
|
if (str != null)
|
|
return Bitter.ToString2(str);
|
|
else
|
|
return "";
|
|
}
|
|
|
|
public static void ShowConfigDetailed(ServiceConfig config)
|
|
{
|
|
if (config.ServiceName == null) {
|
|
Console.WriteLine("Error: A ServiceConfig structure had a null ServiceName field.");
|
|
return;
|
|
}
|
|
string! serviceName = Bitter.ToString2(config.ServiceName);
|
|
|
|
string! executableName = config.ExecutableName != null ? Bitter.ToString2(config.ExecutableName) : "";
|
|
string! displayName = config.DisplayName != null ? Bitter.ToString2(config.DisplayName) : "";
|
|
|
|
Console.WriteLine("Service Configuration");
|
|
Console.WriteLine("---------------------");
|
|
Console.WriteLine();
|
|
Console.WriteLine(DetailFormat, "Service Name", serviceName);
|
|
Console.WriteLine(DetailFormat, "Executable", executableName);
|
|
Console.WriteLine(DetailFormat, "Display Name", displayName);
|
|
Console.WriteLine(DetailFormat, "Activation Mode", ServiceEnums.ToString(config.ActivationMode));
|
|
Console.WriteLine(DetailFormat, "Is Disabled?", config.IsAdministrativelyDisabled.ToString());
|
|
|
|
Console.WriteLine(DetailFormat, "Min/Max Processes", String.Format("min {0} / {1}",
|
|
config.MinProcesses,
|
|
config.MaxProcesses == ServiceConfig.UnlimitedProcesses ? "no max" : "max " + config.MaxProcesses));
|
|
|
|
string! max_age_text;
|
|
if (config.MaxProcessAgeInSeconds == ServiceConfig.UnlimitedProcessAge)
|
|
max_age_text = "unlimited";
|
|
else {
|
|
TimeSpan limit = TimeSpan.FromSeconds(config.MaxProcessAgeInSeconds);
|
|
max_age_text = (!)limit.ToString();
|
|
}
|
|
Console.WriteLine(DetailFormat, "Max Process Age", max_age_text);
|
|
|
|
string clients_per_process_text;
|
|
if (config.MaxClientsPerProcess == ServiceConfig.UnlimitedClientsPerProcess) {
|
|
clients_per_process_text = "unlimited";
|
|
}
|
|
else {
|
|
clients_per_process_text = config.MaxClientsPerProcess.ToString();
|
|
}
|
|
Console.WriteLine(DetailFormat, "Max Clients per Process", clients_per_process_text);
|
|
|
|
}
|
|
|
|
const string DetailFormat = "{0,-25}: {1}";
|
|
|
|
public static void ShowStatusDetailed(ServiceStatus status)
|
|
{
|
|
Console.WriteLine("Service Status");
|
|
Console.WriteLine("--------------");
|
|
Console.WriteLine();
|
|
Console.WriteLine(DetailFormat, "State", ServiceEnums.ToString(status.State));
|
|
if (status.State != ServiceState.Stopped) {
|
|
Console.WriteLine(DetailFormat, "Process ID", status.ProcessId);
|
|
}
|
|
|
|
// This is not yet accurate.
|
|
// Console.WriteLine(DetailFormat, "Total Active Clients", status.TotalActiveClients);
|
|
|
|
Console.WriteLine(DetailFormat, "Total Active Processes", status.TotalActiveProcesses);
|
|
Console.WriteLine(DetailFormat, "Connect Queue Length", status.ConnectQueueLength);
|
|
|
|
Console.WriteLine(DetailFormat, "Last Process Start", status.LastStartFailed ? "FAILED" : "Succeeded");
|
|
if (status.LastStartFailed) {
|
|
Console.WriteLine(DetailFormat, "Last Start Error", ServiceEnums.ToString(status.LastStartError));
|
|
}
|
|
}
|
|
}
|
|
|
|
}
|
|
|