PageRenderTime 55ms CodeModel.GetById 14ms RepoModel.GetById 1ms app.codeStats 0ms

/base/Applications/ServiceManager/SMSClient/SMSClient.cs

#
C# | 892 lines | 697 code | 182 blank | 13 comment | 99 complexity | 51fb7ee922ba130f09374531c6bd8feb MD5 | raw file
  1. ///////////////////////////////////////////////////////////////////////////////
  2. //
  3. // Microsoft Research Singularity
  4. //
  5. // Copyright (c) Microsoft Corporation. All rights reserved.
  6. //
  7. // Note: Service Manager client program
  8. //
  9. using System;
  10. using System.Threading;
  11. using Microsoft.SingSharp;
  12. using Microsoft.SingSharp.Reflection;
  13. using Microsoft.Singularity;
  14. using Microsoft.Singularity.Applications;
  15. using Microsoft.Singularity.Channels;
  16. using Microsoft.Singularity.Configuration;
  17. using Microsoft.Singularity.Contracts;
  18. using Microsoft.Singularity.Directory;
  19. using Microsoft.Singularity.Io;
  20. using Microsoft.Singularity.ServiceManager;
  21. [assembly: Transform(typeof(ApplicationResourceTransform))]
  22. namespace Microsoft.Singularity.Applications.ServiceManager
  23. {
  24. [ConsoleCategory(HelpMessage="Service management client", DefaultAction=true)]
  25. internal class DefaultConfig
  26. {
  27. [InputEndpoint("data")]
  28. public readonly TRef<UnicodePipeContract.Exp:READY> Stdin;
  29. [OutputEndpoint("data")]
  30. public readonly TRef<UnicodePipeContract.Imp:READY> Stdout;
  31. reflective internal DefaultConfig();
  32. internal int AppMain()
  33. {
  34. Console.WriteLine("Use -? for help.");
  35. return 0;
  36. }
  37. }
  38. [ConsoleCategory(Action="start", HelpMessage="Start a service")]
  39. internal class StartConfig
  40. {
  41. [InputEndpoint("data")]
  42. public readonly TRef<UnicodePipeContract.Exp:READY> Stdin;
  43. [OutputEndpoint("data")]
  44. public readonly TRef<UnicodePipeContract.Imp:READY> Stdout;
  45. [StringParameter("service", Mandatory=true, Position=0)]
  46. internal string serviceName;
  47. // [BoolParameter("w", Mandatory=false, HelpMessage="Wait for service to start.")]
  48. public bool wait;
  49. reflective internal StartConfig();
  50. internal int AppMain()
  51. {
  52. return SMSClient.StartService((!)serviceName, wait);
  53. }
  54. }
  55. [ConsoleCategory(Action="stop", HelpMessage="Stop a service")]
  56. internal class StopServiceCommand
  57. {
  58. [InputEndpoint("data")]
  59. public readonly TRef<UnicodePipeContract.Exp:READY> Stdin;
  60. [OutputEndpoint("data")]
  61. public readonly TRef<UnicodePipeContract.Imp:READY> Stdout;
  62. [StringParameter("service", Mandatory=true, Position=0)]
  63. internal string serviceName;
  64. // [BoolParameter("w", Mandatory=false, HelpMessage="Wait for service to stop.")]
  65. public bool wait;
  66. reflective internal StopServiceCommand();
  67. internal int AppMain()
  68. {
  69. return SMSClient.StopService((!)serviceName, wait);
  70. }
  71. }
  72. [ConsoleCategory(Action="list", HelpMessage="Show a list of services")]
  73. internal class ListConfig
  74. {
  75. [InputEndpoint("data")]
  76. public readonly TRef<UnicodePipeContract.Exp:READY> Stdin;
  77. [OutputEndpoint("data")]
  78. public readonly TRef<UnicodePipeContract.Imp:READY> Stdout;
  79. reflective internal ListConfig();
  80. internal int AppMain()
  81. {
  82. return SMSClient.ListServices(this);
  83. }
  84. }
  85. [ConsoleCategory(Action="show", HelpMessage="Show details about a specific service.")]
  86. internal class ShowServiceParameters
  87. {
  88. [InputEndpoint("data")]
  89. public readonly TRef<UnicodePipeContract.Exp:READY> Stdin;
  90. [OutputEndpoint("data")]
  91. public readonly TRef<UnicodePipeContract.Imp:READY> Stdout;
  92. [StringParameter("service", Position=0, Mandatory=true, HelpMessage="The service to examine.")]
  93. public string ServiceName;
  94. reflective internal ShowServiceParameters();
  95. internal int AppMain()
  96. {
  97. if (ServiceName == null) {
  98. Console.WriteLine("The 'service' parameter is required, but has not been provided.");
  99. return -1;
  100. }
  101. ServiceManagerContract.Imp! svmanager = SMSClient.ConnectServiceManager();
  102. try {
  103. ServiceError error = SMSClient.SelectService(svmanager, this.ServiceName);
  104. if (error != ServiceError.None)
  105. return -1;
  106. bool errors = false;
  107. svmanager.SendQueryServiceConfig();
  108. switch receive {
  109. case svmanager.CurrentServiceConfig(config):
  110. SMSClient.ShowConfigDetailed(config);
  111. config.Dispose();
  112. break;
  113. case svmanager.RequestFailed(err):
  114. if (err == ServiceError.ServiceNotFound) {
  115. Console.WriteLine("There is no service with name '{0}'.", this.ServiceName);
  116. return -1;
  117. }
  118. Console.WriteLine("Failed to query service configuration.");
  119. SMSClient.ShowServiceError(err);
  120. errors = true;
  121. break;
  122. case svmanager.ChannelClosed():
  123. Console.WriteLine("The Service Manager closed its channel unexpectedly.");
  124. return -1;
  125. }
  126. svmanager.SendQueryServiceStatus();
  127. switch receive {
  128. case svmanager.CurrentServiceStatus(status):
  129. Console.WriteLine();
  130. SMSClient.ShowStatusDetailed(status);
  131. status.Dispose();
  132. break;
  133. case svmanager.RequestFailed(err):
  134. Console.WriteLine("Failed to query service status.");
  135. SMSClient.ShowServiceError(err);
  136. errors = true;
  137. break;
  138. case svmanager.ChannelClosed():
  139. Console.WriteLine("The Service Manager closed its channel unexpectedly.");
  140. return -1;
  141. }
  142. if (errors)
  143. return -1;
  144. else
  145. return 0;
  146. }
  147. finally {
  148. delete svmanager;
  149. }
  150. }
  151. }
  152. [ConsoleCategory(Action="watch", HelpMessage="Watch the status of a service")]
  153. internal class WatchConfig
  154. {
  155. [InputEndpoint("data")]
  156. public readonly TRef<UnicodePipeContract.Exp:READY> Stdin;
  157. [OutputEndpoint("data")]
  158. public readonly TRef<UnicodePipeContract.Imp:READY> Stdout;
  159. [StringParameter("service", Mandatory=true, Position=0)]
  160. internal string serviceName;
  161. reflective internal WatchConfig();
  162. internal int AppMain()
  163. {
  164. return SMSClient.WatchService((!)serviceName);
  165. }
  166. }
  167. [ConsoleCategory(Action="watchall", HelpMessage="Watch the status of the Service Manager")]
  168. internal class WatchAllConfig
  169. {
  170. [InputEndpoint("data")]
  171. public readonly TRef<UnicodePipeContract.Exp:READY> Stdin;
  172. [OutputEndpoint("data")]
  173. public readonly TRef<UnicodePipeContract.Imp:READY> Stdout;
  174. #if false
  175. [BoolParameter("c", Mandatory=false, HelpMessage="Watch all service configuration changes")]
  176. public bool watchConfigChanges;
  177. [BoolParameter("s", Mandatory=false, HelpMessage="Watch all service status changes")]
  178. public bool watchStatusChanges;
  179. #endif
  180. reflective internal WatchAllConfig();
  181. internal int AppMain()
  182. {
  183. #if false
  184. ServiceManagerEventMask desiredEvents = 0;
  185. if (watchConfigChanges)
  186. desiredEvents |= ServiceManagerEventMask.AnyServiceConfig;
  187. if (watchStatusChanges)
  188. desiredEvents |= ServiceManagerEventMask.AnyServiceStatus;
  189. if (desiredEvents == 0)
  190. desiredEvents = ServiceManagerEventMask.AnyServiceConfig | ServiceManagerEventMask.AnyServiceStatus;
  191. #else
  192. ServiceManagerEventMask desiredEvents = ServiceManagerEventMask.AnyServiceConfig | ServiceManagerEventMask.AnyServiceStatus;
  193. #endif
  194. ServiceManagerContract.Imp! svmanager = SMSClient.ConnectServiceManager();
  195. svmanager.SendWatchServiceManager(desiredEvents);
  196. switch receive {
  197. case svmanager.Ok():
  198. break;
  199. case svmanager.RequestFailed(error):
  200. Console.WriteLine("The Service Manager rejected the subscription request.");
  201. SMSClient.ShowServiceError(error);
  202. delete svmanager;
  203. return -1;
  204. }
  205. Console.WriteLine("Watching Service Manager...");
  206. for (;;) {
  207. Console.WriteLine("Sending WaitNextServiceManagerChange");
  208. svmanager.SendWaitNextServiceManagerChange();
  209. Console.WriteLine("switch-receive");
  210. switch receive {
  211. case svmanager.ServiceManagerChanged(events):
  212. Console.WriteLine("Service Manager events fired: {0:x8}", ((uint)events));
  213. break;
  214. }
  215. }
  216. }
  217. }
  218. [ConsoleCategory(Action="create", HelpMessage="Create a new service entry")]
  219. internal class CreateServiceCommand
  220. {
  221. [InputEndpoint("data")]
  222. public readonly TRef<UnicodePipeContract.Exp:READY> Stdin;
  223. [OutputEndpoint("data")]
  224. public readonly TRef<UnicodePipeContract.Imp:READY> Stdout;
  225. [StringParameter("service", Mandatory=true, Position=0)]
  226. internal string serviceName;
  227. [StringParameter("exe", Mandatory=false, HelpMessage="Executable to use; if omitted, uses service name.")]
  228. public string executableName;
  229. [StringParameter("display", Mandatory=false, HelpMessage="Display name to use; if omitted, uses service name.")]
  230. public string displayName;
  231. [BoolParameter("disabled", Mandatory=false, HelpMessage="Create in a disabled state.")]
  232. public bool isAdministrativelyDisabled;
  233. reflective internal CreateServiceCommand();
  234. internal int AppMain()
  235. {
  236. assert serviceName != null;
  237. if (serviceName.Length == 0) {
  238. Console.WriteLine("Invalid service name.");
  239. return -1;
  240. }
  241. if (executableName == null || executableName.Length == 0)
  242. executableName = serviceName;
  243. if (displayName == null || displayName.Length == 0)
  244. displayName = serviceName;
  245. ServiceManagerContract.Imp! svmanager = SMSClient.ConnectServiceManager();
  246. try {
  247. ServiceConfig config = new ServiceConfig();
  248. config.ServiceName = Bitter.FromString2(serviceName);
  249. config.ExecutableName = Bitter.FromString2(executableName);
  250. config.DisplayName = Bitter.FromString2(displayName);
  251. config.IsAdministrativelyDisabled = isAdministrativelyDisabled;
  252. config.MinProcesses = 0;
  253. config.MaxProcesses = 1;
  254. config.MaxClientsPerProcess = ServiceConfig.UnlimitedClientsPerProcess;
  255. config.MaxProcessAgeInSeconds = ServiceConfig.UnlimitedProcessAge;
  256. svmanager.SendCreateService(config);
  257. switch receive {
  258. case svmanager.Ok():
  259. Console.WriteLine("Service was successfully created.");
  260. return 0;
  261. case svmanager.RequestFailed(error):
  262. Console.WriteLine("Failed to create service.");
  263. SMSClient.ShowServiceError(error);
  264. return -1;
  265. }
  266. }
  267. finally {
  268. delete svmanager;
  269. }
  270. }
  271. }
  272. [ConsoleCategory(Action="delete", HelpMessage="Delete an existing service")]
  273. internal class DeleteServiceCommand
  274. {
  275. [InputEndpoint("data")]
  276. public readonly TRef<UnicodePipeContract.Exp:READY> Stdin;
  277. [OutputEndpoint("data")]
  278. public readonly TRef<UnicodePipeContract.Imp:READY> Stdout;
  279. [StringParameter("service", Mandatory=true, Position=0)]
  280. internal string serviceName;
  281. reflective internal DeleteServiceCommand();
  282. internal int AppMain()
  283. {
  284. assert serviceName != null;
  285. if (serviceName.Length == 0) {
  286. Console.WriteLine("Invalid service name.");
  287. return -1;
  288. }
  289. ServiceManagerContract.Imp! svmanager = SMSClient.ConnectServiceManager();
  290. try {
  291. ServiceError error = SMSClient.SelectService(svmanager, serviceName);
  292. if (error != ServiceError.None)
  293. return -1;
  294. svmanager.SendDeleteService();
  295. switch receive {
  296. case svmanager.Ok():
  297. Console.WriteLine("Service was successfully deleted.");
  298. return 0;
  299. case svmanager.RequestFailed(err):
  300. Console.WriteLine("Failed to delete service.");
  301. SMSClient.ShowServiceError(err);
  302. return -1;
  303. }
  304. }
  305. finally {
  306. delete svmanager;
  307. }
  308. }
  309. }
  310. [ConsoleCategory(Action="enable", HelpMessage="Enable a service")]
  311. internal class EnableServiceCommand
  312. {
  313. [InputEndpoint("data")]
  314. public readonly TRef<UnicodePipeContract.Exp:READY> Stdin;
  315. [OutputEndpoint("data")]
  316. public readonly TRef<UnicodePipeContract.Imp:READY> Stdout;
  317. [StringParameter("service", Mandatory=true, Position=0)]
  318. internal string serviceName;
  319. reflective internal EnableServiceCommand();
  320. internal int AppMain()
  321. {
  322. assert serviceName != null;
  323. if (serviceName.Length == 0) {
  324. Console.WriteLine("Invalid service name.");
  325. return -1;
  326. }
  327. ServiceManagerContract.Imp! svmanager = SMSClient.ConnectServiceManager();
  328. try {
  329. ServiceError error = SMSClient.SelectService(svmanager, serviceName);
  330. if (error != ServiceError.None)
  331. return -1;
  332. svmanager.SendEnableService(true);
  333. switch receive {
  334. case svmanager.Ok():
  335. Console.WriteLine("Service was successfully enabled.");
  336. return 0;
  337. case svmanager.RequestFailed(err):
  338. Console.WriteLine("Failed to enable service.");
  339. SMSClient.ShowServiceError(err);
  340. return -1;
  341. }
  342. }
  343. finally {
  344. delete svmanager;
  345. }
  346. }
  347. }
  348. [ConsoleCategory(Action="disable", HelpMessage="Disable a service")]
  349. internal class DisableServiceCommand
  350. {
  351. [InputEndpoint("data")]
  352. public readonly TRef<UnicodePipeContract.Exp:READY> Stdin;
  353. [OutputEndpoint("data")]
  354. public readonly TRef<UnicodePipeContract.Imp:READY> Stdout;
  355. [StringParameter("service", Mandatory=true, Position=0)]
  356. internal string serviceName;
  357. reflective internal DisableServiceCommand();
  358. internal int AppMain()
  359. {
  360. assert serviceName != null;
  361. if (serviceName.Length == 0) {
  362. Console.WriteLine("Invalid service name.");
  363. return -1;
  364. }
  365. ServiceManagerContract.Imp! svmanager = SMSClient.ConnectServiceManager();
  366. try {
  367. ServiceError error = SMSClient.SelectService(svmanager, serviceName);
  368. if (error != ServiceError.None)
  369. return -1;
  370. svmanager.SendEnableService(false);
  371. switch receive {
  372. case svmanager.Ok():
  373. Console.WriteLine("Service was successfully disabled.");
  374. return 0;
  375. case svmanager.RequestFailed(err):
  376. Console.WriteLine("Failed to disable service.");
  377. SMSClient.ShowServiceError(err);
  378. return -1;
  379. }
  380. }
  381. finally {
  382. delete svmanager;
  383. }
  384. }
  385. }
  386. [ConsoleCategory(Action="kill", HelpMessage="Terminate the process(es) of a service.")]
  387. internal class TerminateServiceCommand
  388. {
  389. [InputEndpoint("data")]
  390. public readonly TRef<UnicodePipeContract.Exp:READY> Stdin;
  391. [OutputEndpoint("data")]
  392. public readonly TRef<UnicodePipeContract.Imp:READY> Stdout;
  393. [StringParameter("service", Mandatory=true, Position=0)]
  394. internal string serviceName;
  395. [LongParameter("pid", Mandatory=false, Position=1, Default=-1)]
  396. internal long processId;
  397. reflective internal TerminateServiceCommand();
  398. internal int AppMain()
  399. {
  400. assert serviceName != null;
  401. if (serviceName.Length == 0) {
  402. Console.WriteLine("Invalid service name.");
  403. return -1;
  404. }
  405. ServiceManagerContract.Imp! svmanager = SMSClient.ConnectServiceManager();
  406. try {
  407. ServiceError error = SMSClient.SelectService(svmanager, serviceName);
  408. if (error != ServiceError.None)
  409. return -1;
  410. if (processId != -1)
  411. svmanager.SendTerminateServiceProcess((int)processId);
  412. else
  413. svmanager.SendTerminateServiceAllProcesses();
  414. switch receive {
  415. case svmanager.Ok():
  416. return 0;
  417. case svmanager.RequestFailed(err):
  418. SMSClient.ShowServiceError(err);
  419. return -1;
  420. }
  421. }
  422. finally {
  423. delete svmanager;
  424. }
  425. }
  426. }
  427. public class SMSClient
  428. {
  429. internal static ServiceManagerContract.Imp! ConnectServiceManager()
  430. {
  431. using (ImpatientWatcher watcher = new ImpatientWatcher("ConnectServiceManager", "create channel", 250)) {
  432. ErrorCode error;
  433. ServiceManagerContract.Imp! manager_imp;
  434. ServiceManagerContract.Exp! manager_exp;
  435. ServiceManagerContract.NewChannel(out manager_imp, out manager_exp);
  436. watcher.NextStep("NewClientEndpoint", 250);
  437. DirectoryServiceContract.Imp! rootds = DirectoryService.NewClientEndpoint();
  438. try {
  439. watcher.NextStep("SdsUtils.Bind", 1000);
  440. if (SdsUtils.Bind(ServiceManagerContract.ModuleName, rootds, manager_exp, out error)) {
  441. watcher.NextStep("RecvSuccess", 250);
  442. manager_imp.RecvSuccess();
  443. return manager_imp;
  444. }
  445. else {
  446. delete manager_imp;
  447. Console.WriteLine("Failed to contact the Service Manager. Error: " + SdsUtils.ErrorCodeToString(error));
  448. throw new Exception("Failed to connect to Service Manager.");
  449. }
  450. }
  451. finally {
  452. delete rootds;
  453. }
  454. }
  455. }
  456. internal static ServiceError SelectService(ServiceManagerContract.Imp! svmanager, string! serviceName)
  457. {
  458. svmanager.SendSelectService(Bitter.FromString2(serviceName));
  459. switch receive {
  460. case svmanager.Ok():
  461. // Console.WriteLine("Successfully selected service '{0}'.", serviceName);
  462. return ServiceError.None;
  463. case svmanager.RequestFailed(error):
  464. Console.WriteLine("Failed to select service '{0}'.", serviceName);
  465. ShowServiceError(error);
  466. return error;
  467. case svmanager.ChannelClosed():
  468. throw new Exception("Service Manager closed channel before responding.");
  469. }
  470. }
  471. internal static void ShowServiceError(ServiceError error)
  472. {
  473. Console.WriteLine("ServiceError: " + ServiceEnums.ToString(error));
  474. }
  475. static internal int StartService(string! serviceName, bool wait)
  476. {
  477. ServiceManagerContract.Imp! svmanager = ConnectServiceManager();
  478. try {
  479. ServiceError error = SelectService(svmanager, serviceName);
  480. if (error != ServiceError.None) {
  481. return -1;
  482. }
  483. if (wait) {
  484. svmanager.SendStartServiceWait();
  485. for (;;) {
  486. switch receive {
  487. case svmanager.RequestFailed(err):
  488. ShowServiceError(err);
  489. return -1;
  490. case svmanager.ServiceStarting():
  491. Console.WriteLine("Service Manager accepted request to start service '{0}'.", serviceName);
  492. return 0;
  493. case timeout(TimeSpan.FromSeconds(10)):
  494. Console.WriteLine("waiting...");
  495. break;
  496. }
  497. }
  498. }
  499. else {
  500. svmanager.SendStartServiceNoWait();
  501. switch receive {
  502. case svmanager.RequestFailed(err):
  503. ShowServiceError(err);
  504. return -1;
  505. case svmanager.ServiceStarting():
  506. Console.WriteLine("Service Manager accepted request to start service '{0}'.", serviceName);
  507. return 0;
  508. }
  509. }
  510. }
  511. finally {
  512. delete svmanager;
  513. }
  514. }
  515. internal static int StopService(string! serviceName, bool wait)
  516. {
  517. ServiceManagerContract.Imp! svmanager = ConnectServiceManager();
  518. try {
  519. ServiceError error = SelectService(svmanager, serviceName);
  520. if (error != ServiceError.None)
  521. return -1;
  522. if (wait) {
  523. svmanager.SendStopServiceWait();
  524. for (;;) {
  525. switch receive {
  526. case svmanager.RequestFailed(err):
  527. ShowServiceError(err);
  528. if (err == ServiceError.CannotStopService) {
  529. Console.WriteLine("If this service is an 'always active' service, then the stop command cannot be used.");
  530. Console.WriteLine("Instead, use the 'disable' command.");
  531. }
  532. return -1;
  533. case svmanager.ServiceStopping():
  534. Console.WriteLine("Service Manager accepted request to stop service '{0}'.", serviceName);
  535. return 0;
  536. case timeout(TimeSpan.FromSeconds(10)):
  537. Console.WriteLine("waiting...");
  538. break;
  539. }
  540. }
  541. }
  542. else {
  543. svmanager.SendStopServiceNoWait();
  544. switch receive {
  545. case svmanager.RequestFailed(err):
  546. ShowServiceError(err);
  547. return -1;
  548. case svmanager.ServiceStopping():
  549. Console.WriteLine("Service Manager accepted request to stop service '{0}'.", serviceName);
  550. return 0;
  551. }
  552. }
  553. }
  554. finally {
  555. delete svmanager;
  556. }
  557. }
  558. internal static int WatchService(string! serviceName)
  559. {
  560. ServiceManagerContract.Imp! svmanager = ConnectServiceManager();
  561. try {
  562. ServiceError error = SelectService(svmanager, serviceName);
  563. if (error != ServiceError.None) {
  564. return -1;
  565. }
  566. svmanager.SendWatchServiceStatus();
  567. switch receive {
  568. case svmanager.RequestFailed(err):
  569. ShowServiceError(err);
  570. return -1;
  571. case svmanager.Ok():
  572. Console.WriteLine("Service Manager accepted request to watch service '{0}'.", serviceName);
  573. break;
  574. }
  575. for (;;) {
  576. svmanager.SendWaitServiceChange();
  577. switch receive {
  578. case svmanager.ServiceStatusChanged(ServiceStatus status, bool missedChange):
  579. Console.WriteLine("Status changed: ");
  580. Console.WriteLine(" State: " + ServiceEnums.ToString(status.State));
  581. if (missedChange) {
  582. Console.WriteLine(" Note: At least one status change was missed.");
  583. }
  584. break;
  585. case svmanager.RequestFailed(err):
  586. Console.WriteLine("Request failed.");
  587. ShowServiceError(err);
  588. return -1;
  589. case svmanager.ChannelClosed():
  590. Console.WriteLine("Service Manager closed channel!");
  591. return -1;
  592. }
  593. }
  594. }
  595. finally {
  596. delete svmanager;
  597. }
  598. }
  599. const string ListServiceFormat = "{0,-20} {1,-10} {2,-6} {3}";
  600. internal static int ListServices(ListConfig! config)
  601. {
  602. ServiceManagerContract.Imp! svmanager = ConnectServiceManager();
  603. try {
  604. Console.WriteLine(ListServiceFormat, "Name", "State", "PID", "Display Name");
  605. Console.WriteLine(ListServiceFormat,
  606. new String('-', 20),
  607. new String('-', 10),
  608. new String('-', 6),
  609. new String('-', 30));
  610. ServiceInfo[]! in ExHeap first_entries = new[ExHeap] ServiceInfo[40];
  611. svmanager.SendEnumerateServices(first_entries);
  612. for (;;) {
  613. switch receive {
  614. case svmanager.EnumerationTerminated(entries, count):
  615. ListServices(entries, count);
  616. delete entries;
  617. return 0;
  618. case svmanager.NextServiceInfo(entries, count):
  619. ListServices(entries, count);
  620. svmanager.SendEnumerateServices(entries);
  621. break;
  622. case svmanager.ChannelClosed():
  623. Console.WriteLine("Service Manager channel closed");
  624. return -1;
  625. }
  626. }
  627. }
  628. finally {
  629. delete svmanager;
  630. }
  631. }
  632. static void ListServices(ServiceInfo[]! in ExHeap entries, int count)
  633. {
  634. for (int i = 0; i < count; i++) {
  635. expose(entries[i])
  636. {
  637. string! serviceName = ToString(entries[i].Config.ServiceName);
  638. string! displayName = ToString(entries[i].Config.DisplayName);
  639. string! stateString = ServiceEnums.ToString(entries[i].Status.State);
  640. string! processIdString = entries[i].Status.ProcessId != -1 ?
  641. (!)entries[i].Status.ProcessId.ToString() : "";
  642. Console.WriteLine(ListServiceFormat, serviceName, stateString, processIdString, displayName);
  643. }
  644. }
  645. }
  646. public static string! ToString(char[] in ExHeap str)
  647. {
  648. if (str != null)
  649. return Bitter.ToString2(str);
  650. else
  651. return "";
  652. }
  653. public static void ShowConfigDetailed(ServiceConfig config)
  654. {
  655. if (config.ServiceName == null) {
  656. Console.WriteLine("Error: A ServiceConfig structure had a null ServiceName field.");
  657. return;
  658. }
  659. string! serviceName = Bitter.ToString2(config.ServiceName);
  660. string! executableName = config.ExecutableName != null ? Bitter.ToString2(config.ExecutableName) : "";
  661. string! displayName = config.DisplayName != null ? Bitter.ToString2(config.DisplayName) : "";
  662. Console.WriteLine("Service Configuration");
  663. Console.WriteLine("---------------------");
  664. Console.WriteLine();
  665. Console.WriteLine(DetailFormat, "Service Name", serviceName);
  666. Console.WriteLine(DetailFormat, "Executable", executableName);
  667. Console.WriteLine(DetailFormat, "Display Name", displayName);
  668. Console.WriteLine(DetailFormat, "Activation Mode", ServiceEnums.ToString(config.ActivationMode));
  669. Console.WriteLine(DetailFormat, "Is Disabled?", config.IsAdministrativelyDisabled.ToString());
  670. Console.WriteLine(DetailFormat, "Min/Max Processes", String.Format("min {0} / {1}",
  671. config.MinProcesses,
  672. config.MaxProcesses == ServiceConfig.UnlimitedProcesses ? "no max" : "max " + config.MaxProcesses));
  673. string! max_age_text;
  674. if (config.MaxProcessAgeInSeconds == ServiceConfig.UnlimitedProcessAge)
  675. max_age_text = "unlimited";
  676. else {
  677. TimeSpan limit = TimeSpan.FromSeconds(config.MaxProcessAgeInSeconds);
  678. max_age_text = (!)limit.ToString();
  679. }
  680. Console.WriteLine(DetailFormat, "Max Process Age", max_age_text);
  681. string clients_per_process_text;
  682. if (config.MaxClientsPerProcess == ServiceConfig.UnlimitedClientsPerProcess) {
  683. clients_per_process_text = "unlimited";
  684. }
  685. else {
  686. clients_per_process_text = config.MaxClientsPerProcess.ToString();
  687. }
  688. Console.WriteLine(DetailFormat, "Max Clients per Process", clients_per_process_text);
  689. }
  690. const string DetailFormat = "{0,-25}: {1}";
  691. public static void ShowStatusDetailed(ServiceStatus status)
  692. {
  693. Console.WriteLine("Service Status");
  694. Console.WriteLine("--------------");
  695. Console.WriteLine();
  696. Console.WriteLine(DetailFormat, "State", ServiceEnums.ToString(status.State));
  697. if (status.State != ServiceState.Stopped) {
  698. Console.WriteLine(DetailFormat, "Process ID", status.ProcessId);
  699. }
  700. // This is not yet accurate.
  701. // Console.WriteLine(DetailFormat, "Total Active Clients", status.TotalActiveClients);
  702. Console.WriteLine(DetailFormat, "Total Active Processes", status.TotalActiveProcesses);
  703. Console.WriteLine(DetailFormat, "Connect Queue Length", status.ConnectQueueLength);
  704. Console.WriteLine(DetailFormat, "Last Process Start", status.LastStartFailed ? "FAILED" : "Succeeded");
  705. if (status.LastStartFailed) {
  706. Console.WriteLine(DetailFormat, "Last Start Error", ServiceEnums.ToString(status.LastStartError));
  707. }
  708. }
  709. }
  710. }