Source code of Windows XP (NT5)
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

761 lines
16 KiB

  1. /*++
  2. Copyright (c) 1992 Microsoft Corporation
  3. Module Name:
  4. gencmd.c
  5. Abstract:
  6. Resource DLL for Generic Command line services.
  7. This is a modified version of generic app.
  8. Online and offline events each create a command window, execute a command,
  9. then delete the command window.
  10. Author:
  11. Rod Gamache (rodga) 8-Jan-1996
  12. Robs - modified to make gencmd version
  13. Revision History:
  14. --*/
  15. #define UNICODE 1
  16. #include "windows.h"
  17. #include "stdio.h"
  18. #include "clusapi.h"
  19. #include "resapi.h"
  20. #define MAX_APPS 200
  21. #define GENCMD_PRINT printf
  22. typedef struct _MY_PROCESS_INFORMATION {
  23. PROCESS_INFORMATION;
  24. ULONG Index;
  25. RESOURCE_HANDLE ResourceHandle;
  26. PTSTR AppName;
  27. PTSTR OnCommandLine;
  28. PTSTR OffCommandLine;
  29. PTSTR CurDir;
  30. } MY_PROCESS_INFORMATION, *PMY_PROCESS_INFORMATION;
  31. //
  32. // Global Data
  33. //
  34. // Lock to protect the ProcessInfo table
  35. CRITICAL_SECTION ProcessLock;
  36. // The list of handles for active apps
  37. PMY_PROCESS_INFORMATION ProcessInfo[MAX_APPS];
  38. // Event Logging routine
  39. PLOG_EVENT_ROUTINE GenCmdLogEvent = NULL;
  40. extern CLRES_FUNCTION_TABLE GenCmdFunctionTable;
  41. //
  42. // Forward routines
  43. //
  44. LPWSTR
  45. GetParameter(
  46. IN HKEY ClusterKey,
  47. IN LPCWSTR ValueName
  48. );
  49. BOOLEAN
  50. GenCmdInit(
  51. VOID
  52. )
  53. {
  54. InitializeCriticalSection( &ProcessLock );
  55. return(TRUE);
  56. }
  57. BOOLEAN
  58. WINAPI
  59. GenCmdDllEntryPoint(
  60. IN HINSTANCE DllHandle,
  61. IN DWORD Reason,
  62. IN LPVOID Reserved
  63. )
  64. {
  65. switch( Reason ) {
  66. case DLL_PROCESS_ATTACH:
  67. if ( !GenCmdInit() ) {
  68. return(FALSE);
  69. }
  70. break;
  71. case DLL_PROCESS_DETACH:
  72. break;
  73. default:
  74. break;
  75. }
  76. return(TRUE);
  77. } // GenCmd DllEntryPoint
  78. DWORD
  79. WINAPI
  80. Startup(
  81. IN LPCWSTR ResourceType,
  82. IN DWORD MinVersionSupported,
  83. IN DWORD MaxVersionSupported,
  84. IN PSET_RESOURCE_STATUS_ROUTINE SetResourceStatus,
  85. IN PLOG_EVENT_ROUTINE LogEvent,
  86. OUT PCLRES_FUNCTION_TABLE *FunctionTable
  87. )
  88. /*++
  89. Routine Description:
  90. Startup a particular resource type. This means verifying the version
  91. requested, and returning the function table for this resource type.
  92. Arguments:
  93. ResourceType - Supplies the type of resource.
  94. MinVersionSupported - The minimum version number supported by the cluster
  95. service on this system.
  96. MaxVersionSupported - The maximum version number supported by the cluster
  97. service on this system.
  98. FunctionTable - Returns the Function Table for this resource type.
  99. Return Value:
  100. ERROR_SUCCESS if successful.
  101. A Win32 error code on failure.
  102. --*/
  103. {
  104. if ( _wcsicmp( ResourceType, L"Generic Command" ) != 0 ) {
  105. return(ERROR_UNKNOWN_REVISION);
  106. }
  107. if ( (MinVersionSupported <= CLRES_VERSION_V1_00) &&
  108. (MaxVersionSupported >= CLRES_VERSION_V1_00) ) {
  109. *FunctionTable = &GenCmdFunctionTable;
  110. return(ERROR_SUCCESS);
  111. }
  112. GenCmdLogEvent = LogEvent;
  113. return(ERROR_REVISION_MISMATCH);
  114. } // Startup
  115. RESID
  116. WINAPI
  117. GenCmdOpen(
  118. IN LPCWSTR ResourceName,
  119. IN HKEY ResourceKey,
  120. IN RESOURCE_HANDLE ResourceHandle
  121. )
  122. /*++
  123. Routine Description:
  124. Open routine for generic service resource.
  125. Arguments:
  126. ResourceName - supplies the resource name
  127. ResourceKey - supplies a handle to the resource's cluster registry key
  128. ResourceHandle - the resource handle to be supplied with SetResourceStatus
  129. is called.
  130. Return Value:
  131. RESID of created resource
  132. Zero on failure
  133. --*/
  134. {
  135. ULONG index;
  136. RESID appResid = 0;
  137. DWORD errorCode;
  138. HKEY parametersKey = NULL;
  139. PMY_PROCESS_INFORMATION processInfo = NULL;
  140. DWORD paramNameSize = 0;
  141. DWORD paramNameMaxSize = 0;
  142. // Create Process parameters
  143. LPWSTR appName;
  144. LPWSTR OncommandLine;
  145. LPWSTR OffcommandLine;
  146. LPWSTR curDir;
  147. //
  148. // Get registry parameters for this resource.
  149. //
  150. (GenCmdLogEvent)(
  151. ResourceHandle,
  152. LOG_INFORMATION,
  153. L"Creating generic command resource.\n" );
  154. errorCode = ClusterRegOpenKey( ResourceKey,
  155. L"Parameters",
  156. KEY_READ,
  157. &parametersKey );
  158. if ( errorCode != NO_ERROR ) {
  159. (GenCmdLogEvent)(
  160. ResourceHandle,
  161. LOG_ERROR,
  162. L"Unable to open parameters key. Error: %1!u!.\n",
  163. errorCode);
  164. goto error_exit;
  165. }
  166. //
  167. // Read our parameters.
  168. //
  169. // Get the ImageName parameter
  170. appName = GetParameter(parametersKey, L"ImageName");
  171. if ( appName == NULL ) {
  172. (GenCmdLogEvent)(
  173. ResourceHandle,
  174. LOG_ERROR,
  175. L"Unable to read ImageName parameter. Error: %1!u!.\n",
  176. GetLastError() );
  177. goto error_exit;
  178. }
  179. // Get the CommandLine parameter
  180. OncommandLine = GetParameter(parametersKey, L"OnCommandLine");
  181. if ( OncommandLine == NULL ) {
  182. (GenCmdLogEvent)(
  183. ResourceHandle,
  184. LOG_INFORMATION,
  185. L"Resource create request but no Online command supplied.\n");
  186. OncommandLine = L"";
  187. }
  188. OffcommandLine = GetParameter(parametersKey, L"OffCommandLine");
  189. if ( OncommandLine == NULL ) {
  190. (GenCmdLogEvent)(
  191. ResourceHandle,
  192. LOG_INFORMATION,
  193. L"Resource create request but no Offline command supplied.\n");
  194. OncommandLine = L"";
  195. }
  196. // Get the CurrentDirectory parameter
  197. curDir = GetParameter(parametersKey, L"CurrentDirectory");
  198. if ( (curDir == NULL) ||
  199. (wcslen(curDir) == 0) ) {
  200. curDir = NULL;
  201. }
  202. //
  203. // Find a free index in the process info table for this new app.
  204. //
  205. EnterCriticalSection( &ProcessLock );
  206. for ( index = 1; index <= MAX_APPS; index++ ) {
  207. if ( ProcessInfo[index-1] == NULL ) {
  208. break;
  209. }
  210. }
  211. // Check if there was room in the process table.
  212. if ( index > MAX_APPS ) {
  213. LeaveCriticalSection( &ProcessLock );
  214. (GenCmdLogEvent)(
  215. ResourceHandle,
  216. LOG_ERROR,
  217. L"Too many applications to watch.\n");
  218. goto error_exit;
  219. }
  220. processInfo = LocalAlloc( LMEM_FIXED, sizeof(MY_PROCESS_INFORMATION) );
  221. if ( processInfo == NULL ) {
  222. LeaveCriticalSection( &ProcessLock );
  223. (GenCmdLogEvent)(
  224. ResourceHandle,
  225. LOG_ERROR,
  226. L"Failed to allocate a process info structure.\n");
  227. goto error_exit;
  228. }
  229. ProcessInfo[index-1] = processInfo;
  230. LeaveCriticalSection( &ProcessLock );
  231. ZeroMemory( processInfo, sizeof(MY_PROCESS_INFORMATION) );
  232. processInfo->Index = index;
  233. processInfo->AppName = appName;
  234. processInfo->OnCommandLine = OncommandLine;
  235. processInfo->OffCommandLine = OffcommandLine;
  236. processInfo->CurDir = curDir;
  237. processInfo->ResourceHandle = ResourceHandle;
  238. appResid = (RESID)index;
  239. error_exit:
  240. if ( parametersKey != NULL ) {
  241. ClusterRegCloseKey( parametersKey );
  242. }
  243. if ( (appResid == 0) && (processInfo != NULL) ) {
  244. ProcessInfo[processInfo->Index] = NULL;
  245. LocalFree( processInfo );
  246. }
  247. return(appResid);
  248. } // GenCmdOpen
  249. DWORD
  250. WINAPI
  251. GenCmdOnline(
  252. IN RESID Resource,
  253. IN OUT PHANDLE EventHandle
  254. )
  255. /*++
  256. Routine Description:
  257. Online routine for Generic Application resource.
  258. Arguments:
  259. Resource - supplies resource id to be brought online
  260. EventHandle - supplies a pointer to a handle to signal on error.
  261. Return Value:
  262. ERROR_SUCCESS if successful.
  263. ERROR_RESOURCE_NOT_FOUND if RESID is not valid.
  264. ERROR_RESOURCE_NOT_AVAILABLE if resource was arbitrated but failed to
  265. acquire 'ownership'.
  266. Win32 error code if other failure.
  267. --*/
  268. {
  269. PMY_PROCESS_INFORMATION processInfo;
  270. DWORD status = ERROR_SUCCESS;
  271. DWORD index;
  272. SECURITY_ATTRIBUTES process = {0};
  273. SECURITY_ATTRIBUTES thread = {0};
  274. DWORD create = 0;
  275. STARTUPINFO startupInfo = {0};
  276. startupInfo.cb = sizeof(STARTUPINFO);
  277. index = PtrToUlong(Resource) - 1;
  278. processInfo = ProcessInfo[index];
  279. if ( processInfo == NULL ) {
  280. GENCMD_PRINT("GenCmd: Online request for a nonexistent resource id %u.\n",
  281. PtrToUlong(Resource));
  282. return(ERROR_RESOURCE_NOT_FOUND);
  283. }
  284. if ( processInfo->Index != PtrToUlong(Resource) ) {
  285. (GenCmdLogEvent)(
  286. processInfo->ResourceHandle,
  287. LOG_ERROR,
  288. L"Online process index sanity checked failed! Index = %1!u!.\n",
  289. PtrToUlong(Resource));
  290. return(ERROR_RESOURCE_NOT_FOUND);
  291. }
  292. (GenCmdLogEvent)(
  293. processInfo->ResourceHandle,
  294. LOG_ERROR,
  295. L"About to create process, cmd = %1!ws!.\n",
  296. processInfo->OnCommandLine);
  297. if ( !CreateProcess( processInfo->AppName,
  298. processInfo->OnCommandLine,
  299. &process, // Process security attributes
  300. &thread, // Thread security attributes
  301. FALSE, // Don't inherit handles from us
  302. create, // Creation Flags
  303. NULL, // No environmet block
  304. processInfo->CurDir, // Current Directory
  305. &startupInfo, // Startup info
  306. (PPROCESS_INFORMATION)processInfo ) ) {
  307. (GenCmdLogEvent)(
  308. processInfo->ResourceHandle,
  309. LOG_ERROR,
  310. L"Failed to create process. Error: %1!u!.\n",
  311. status = GetLastError() );
  312. return(status);
  313. }
  314. return(status);
  315. } // GenCmdOnline
  316. VOID
  317. WINAPI
  318. GenCmdTerminate(
  319. IN RESID Resource
  320. )
  321. /*++
  322. Routine Description:
  323. Terminate routine for Generic Application resource.
  324. Arguments:
  325. Resource - supplies resource id to be terminated
  326. Return Value:
  327. None.
  328. --*/
  329. {
  330. PMY_PROCESS_INFORMATION processInfo;
  331. DWORD index;
  332. SECURITY_ATTRIBUTES process = {0};
  333. SECURITY_ATTRIBUTES thread = {0};
  334. DWORD create = 0;
  335. STARTUPINFO startupInfo = {0};
  336. DWORD errorCode;
  337. index = PtrToUlong(Resource) - 1;
  338. processInfo = ProcessInfo[index];
  339. if ( processInfo == NULL ) {
  340. GENCMD_PRINT("GenCmd: Offline request for a nonexistent resource id %u.\n",
  341. PtrToUlong(Resource));
  342. return;
  343. }
  344. if ( processInfo->Index != PtrToUlong(Resource) ) {
  345. (GenCmdLogEvent)(
  346. processInfo->ResourceHandle,
  347. LOG_ERROR,
  348. L"Offline process index sanity checked failed! Index = %1!u!.\n",
  349. PtrToUlong(Resource));
  350. return;
  351. }
  352. if ( !CreateProcess( processInfo->AppName,
  353. processInfo->OffCommandLine,
  354. &process, // Process security attributes
  355. &thread, // Thread security attributes
  356. FALSE, // Don't inherit handles from us
  357. create, // Creation Flags
  358. NULL, // No environmet block
  359. processInfo->CurDir, // Current Directory
  360. &startupInfo, // Startup info
  361. (PPROCESS_INFORMATION)processInfo ) ) {
  362. (GenCmdLogEvent)(
  363. processInfo->ResourceHandle,
  364. LOG_ERROR,
  365. L"Offline failed to create process. Error: %1!u!.\n",
  366. GetLastError() );
  367. }
  368. } // GenCmdTerminate
  369. DWORD
  370. WINAPI
  371. GenCmdOffline(
  372. IN RESID Resource
  373. )
  374. /*++
  375. Routine Description:
  376. Offline routine for Generic Command resource.
  377. Arguments:
  378. Resource - supplies the resource to be taken offline
  379. Return Value:
  380. ERROR_SUCCESS - always successful.
  381. --*/
  382. {
  383. GenCmdTerminate( Resource );
  384. return(ERROR_SUCCESS);
  385. } // GenCmdOffline
  386. BOOL
  387. WINAPI
  388. GenCmdIsAlive(
  389. IN RESID Resource
  390. )
  391. /*++
  392. Routine Description:
  393. IsAlive routine for Generice service resource.
  394. Arguments:
  395. Resource - supplies the resource id to be polled.
  396. Return Value:
  397. TRUE - Always, we just pretend everything is fine
  398. --*/
  399. {
  400. return(TRUE);
  401. } // GenCmdIsAlive
  402. BOOL
  403. WINAPI
  404. GenCmdLooksAlive(
  405. IN RESID Resource
  406. )
  407. /*++
  408. Routine Description:
  409. LooksAlive routine for Generic Applications resource.
  410. Arguments:
  411. Resource - supplies the resource id to be polled.
  412. Return Value:
  413. TRUE - Resource looks like it is alive and well
  414. FALSE - Resource looks like it is toast.
  415. --*/
  416. {
  417. PMY_PROCESS_INFORMATION processInfo;
  418. DWORD index;
  419. index = PtrToUlong(Resource) - 1;
  420. processInfo = ProcessInfo[index];
  421. if ( processInfo == NULL ) {
  422. GENCMD_PRINT("GenCmd: Offline request for a nonexistent resource id %u.\n",
  423. PtrToUlong(Resource));
  424. return(FALSE);
  425. }
  426. return(TRUE);
  427. } // GenCmdLooksAlive
  428. VOID
  429. WINAPI
  430. GenCmdClose(
  431. IN RESID Resource
  432. )
  433. /*++
  434. Routine Description:
  435. Close routine for Generic Applications resource.
  436. Arguments:
  437. Resource - supplies resource id to be closed
  438. Return Value:
  439. None.
  440. --*/
  441. {
  442. PMY_PROCESS_INFORMATION processInfo;
  443. DWORD errorCode;
  444. DWORD index;
  445. index = PtrToUlong(Resource) - 1;
  446. processInfo = ProcessInfo[index];
  447. if ( processInfo == NULL ) {
  448. GENCMD_PRINT("GenCmd: Close request for a nonexistent resource id %u\n",
  449. PtrToUlong(Resource));
  450. return;
  451. }
  452. if ( processInfo->Index != PtrToUlong(Resource) ) {
  453. (GenCmdLogEvent)(
  454. processInfo->ResourceHandle,
  455. LOG_ERROR,
  456. L"Close process index sanity check failed! Index = %1!u!.\n",
  457. PtrToUlong(Resource) );
  458. return;
  459. }
  460. (GenCmdLogEvent)(
  461. processInfo->ResourceHandle,
  462. LOG_INFORMATION,
  463. L"Close request for Process%1!d!.\n",
  464. PtrToUlong(Resource));
  465. ProcessInfo[index] = NULL;
  466. LocalFree( processInfo );
  467. } // GenCmdClose
  468. LPWSTR
  469. GetParameter(
  470. IN HKEY ClusterKey,
  471. IN LPCWSTR ValueName
  472. )
  473. /*++
  474. Routine Description:
  475. Queries a REG_SZ parameter out of the registry and allocates the
  476. necessary storage for it.
  477. Arguments:
  478. ClusterKey - Supplies the cluster key where the parameter is stored
  479. ValueName - Supplies the name of the value.
  480. Return Value:
  481. A pointer to a buffer containing the parameter if successful.
  482. NULL if unsuccessful.
  483. --*/
  484. {
  485. LPWSTR Value;
  486. DWORD ValueLength;
  487. DWORD ValueType;
  488. DWORD Status;
  489. ValueLength = 0;
  490. Status = ClusterRegQueryValue(ClusterKey,
  491. ValueName,
  492. &ValueType,
  493. NULL,
  494. &ValueLength);
  495. if ( (Status != ERROR_SUCCESS) &&
  496. (Status != ERROR_MORE_DATA) ) {
  497. SetLastError(Status);
  498. return(NULL);
  499. }
  500. if ( ValueType == REG_SZ ) {
  501. ValueLength += sizeof(UNICODE_NULL);
  502. }
  503. Value = LocalAlloc(LMEM_FIXED, ValueLength);
  504. if (Value == NULL) {
  505. return(NULL);
  506. }
  507. Status = ClusterRegQueryValue(ClusterKey,
  508. ValueName,
  509. &ValueType,
  510. (LPBYTE)Value,
  511. &ValueLength);
  512. if (Status != ERROR_SUCCESS) {
  513. LocalFree(Value);
  514. SetLastError(Status);
  515. Value = NULL;
  516. }
  517. return(Value);
  518. } // GetParameter
  519. //***********************************************************
  520. //
  521. // Define Function Table
  522. //
  523. //***********************************************************
  524. CLRES_V1_FUNCTION_TABLE( GenCmdFunctionTable,
  525. CLRES_VERSION_V1_00,
  526. GenCmd,
  527. NULL,
  528. NULL,
  529. NULL,
  530. NULL );