Leaked source code of windows server 2003
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.

1074 lines
26 KiB

  1. /*++
  2. Copyright (c) 2001 Microsoft Corporation
  3. Module Name:
  4. w3wplist.cxx
  5. Abstract:
  6. implementation for w3wplist utility
  7. Author:
  8. Hamid Mahmood (t-hamidm) 06-08-2001
  9. Revision History:
  10. --*/
  11. #include <precomp.hxx>
  12. #include "w3wplist.hxx"
  13. #include <ntrtl.h>
  14. DECLARE_DEBUG_PRINTS_OBJECT();
  15. DECLARE_DEBUG_VARIABLE();
  16. w3wpList::w3wpList()
  17. /*++
  18. Routine Description:
  19. Constructor.
  20. Arguments:
  21. none
  22. Return Value:
  23. none
  24. --*/
  25. {
  26. m_pdwProcessId = NULL;
  27. m_pszTargetAppPoolId = NULL;
  28. m_dwCurrSizeOfProcessIdArray = 0;
  29. m_chVerbosity = 0;
  30. m_dwNumProcessId = 0;
  31. m_startingIndex = 0;
  32. m_dwTargetPID = 0;
  33. InitializeListHead(&m_listHead);
  34. //
  35. // initialize global data
  36. //
  37. CONSOLE_HANDLER_VAR::g_HAS_CONSOLE_EVENT_OCCURED = FALSE;
  38. CONSOLE_HANDLER_VAR::g_THREAD_EXIT_CODE = 1;
  39. CONSOLE_HANDLER_VAR::g_PROCESS_EXIT_CODE = 1;
  40. }
  41. w3wpList::~w3wpList()
  42. /*++
  43. Routine Description:
  44. Destructor.
  45. Arguments:
  46. none
  47. Return Value:
  48. none
  49. --*/
  50. {
  51. DBG_ASSERT (m_dwCurrSizeOfProcessIdArray == 0);
  52. DBG_ASSERT (m_chVerbosity == 0);
  53. DBG_ASSERT (m_dwNumProcessId == 0);
  54. DBG_ASSERT (m_startingIndex == 0);
  55. DBG_ASSERT (m_dwTargetPID == 0);
  56. DBG_ASSERT (m_pdwProcessId == NULL);
  57. DBG_ASSERT (m_pszTargetAppPoolId == NULL);
  58. DBG_ASSERT (IsListEmpty (&m_listHead) == TRUE );
  59. }
  60. HRESULT
  61. w3wpList::Init( IN UCHAR chVerbosity,
  62. IN BOOL fIsListMode,
  63. IN WCHAR* pszInputAppPoolId,
  64. IN DWORD dwPID
  65. )
  66. /*++
  67. Routine Description:
  68. Initializes all the class members.
  69. Arguments:
  70. chVerbosity -- verbosity level
  71. Return Value:
  72. none
  73. --*/
  74. {
  75. HRESULT hr = S_OK;
  76. SYSTEM_INFO systemInfo;
  77. m_dwCurrSizeOfProcessIdArray = MIN_SIZE;
  78. m_chVerbosity = chVerbosity;
  79. m_fIsListMode = fIsListMode;
  80. m_dwTargetPID = dwPID;
  81. m_startingIndex = 0;
  82. InitializeListHead(&m_listHead);
  83. InitializeCriticalSection(&m_CriticalSection);
  84. m_pdwProcessId = new DWORD[m_dwCurrSizeOfProcessIdArray];
  85. if ( m_pdwProcessId == NULL)
  86. {
  87. hr = HRESULT_FROM_WIN32(GetLastError());
  88. goto end;
  89. }
  90. if ( pszInputAppPoolId != NULL )
  91. {
  92. m_pszTargetAppPoolId = new WCHAR[wcslen(pszInputAppPoolId) + 1];
  93. if ( m_pszTargetAppPoolId == NULL )
  94. {
  95. hr = HRESULT_FROM_WIN32(GetLastError());
  96. goto cleanup;
  97. }
  98. wcscpy ( m_pszTargetAppPoolId,
  99. pszInputAppPoolId );
  100. }
  101. // figure out how to read the num of processors
  102. GetSystemInfo( &systemInfo );
  103. m_dwNumThreads = systemInfo.dwNumberOfProcessors;
  104. goto end;
  105. cleanup:
  106. delete [] m_pdwProcessId;
  107. end:
  108. return hr;
  109. }
  110. VOID w3wpList::DestroyObject()
  111. /*++
  112. Routine Description:
  113. deallocates memory.
  114. Arguments:
  115. none
  116. Return Value:
  117. none
  118. --*/
  119. {
  120. W3WPLIST_NODE* pW3wpListNode = NULL;
  121. PLIST_ENTRY pListEntry = NULL;
  122. m_fIsListMode = FALSE;
  123. m_dwCurrSizeOfProcessIdArray = 0;
  124. m_chVerbosity = 0;
  125. m_dwNumThreads = 0;
  126. m_dwNumProcessId = 0;
  127. m_startingIndex = 0;
  128. m_dwTargetPID = 0;
  129. delete [] m_pdwProcessId;
  130. m_pdwProcessId = NULL;
  131. delete [] m_pszTargetAppPoolId;
  132. m_pszTargetAppPoolId = NULL;
  133. DeleteCriticalSection(&m_CriticalSection);
  134. //
  135. // deleting the link list
  136. //
  137. while ( ! IsListEmpty (&m_listHead) )
  138. {
  139. pListEntry = RemoveHeadList(&m_listHead);
  140. pW3wpListNode = CONTAINING_RECORD ( pListEntry,
  141. W3WPLIST_NODE,
  142. m_listEntry
  143. );
  144. //
  145. // terminate the ProcessDetails obj
  146. // before deleting
  147. //
  148. DBG_ASSERT(pW3wpListNode->CheckSignature());
  149. pW3wpListNode->m_wpDetails.Terminate();
  150. delete pW3wpListNode;
  151. }
  152. pW3wpListNode = NULL;
  153. }
  154. HRESULT
  155. w3wpList::GetProcesses()
  156. /*++
  157. Routine Description:
  158. Gets all the PIDs and starts up threads
  159. to go through them.
  160. Arguments:
  161. None
  162. Return Value:
  163. HRESULT hr -- S_OK if successful, else failed with
  164. error code
  165. --*/
  166. {
  167. BOOL fIsFull = FALSE;
  168. BOOL fCreateThreadFailed = FALSE;
  169. DWORD dwBytesReceived;
  170. DWORD dwBufferSize;
  171. HRESULT hr;
  172. DWORD dwIndex;
  173. DWORD dwCount;
  174. HANDLE* pHandles = NULL;
  175. //
  176. // Enumerate all the processes. Memory is
  177. // re-allocated if the original size
  178. // was not enough.
  179. //
  180. do
  181. {
  182. dwBufferSize = sizeof (DWORD) * m_dwCurrSizeOfProcessIdArray;
  183. if ( EnumProcesses ( m_pdwProcessId,
  184. dwBufferSize,
  185. &dwBytesReceived
  186. ) == FALSE )
  187. {
  188. hr = HRESULT_FROM_WIN32(GetLastError());
  189. goto end;
  190. }
  191. m_dwNumProcessId = dwBytesReceived/sizeof(DWORD);
  192. //
  193. // Check for overflow, if yes increase size of
  194. // m_pdwProcessId array
  195. //
  196. if ( m_dwNumProcessId == m_dwCurrSizeOfProcessIdArray )
  197. {
  198. DWORD * pdwTemp = m_pdwProcessId;
  199. m_dwCurrSizeOfProcessIdArray *= 2;
  200. m_pdwProcessId = new DWORD[m_dwCurrSizeOfProcessIdArray];
  201. delete [] pdwTemp;
  202. pdwTemp = NULL;
  203. if ( m_pdwProcessId == NULL)
  204. {
  205. hr = HRESULT_FROM_WIN32(GetLastError());
  206. goto end;
  207. }
  208. fIsFull = TRUE;
  209. }
  210. else
  211. {
  212. fIsFull = FALSE;
  213. }
  214. } while (fIsFull == TRUE);
  215. //
  216. // enable debug privilege for the current process
  217. //
  218. hr = EnableDebugPrivilege();
  219. if ( hr != S_OK )
  220. {
  221. goto end;
  222. }
  223. //
  224. // Create array for thread handles
  225. //
  226. pHandles = new HANDLE[m_dwNumThreads];
  227. if ( pHandles == NULL )
  228. {
  229. hr = HRESULT_FROM_WIN32(GetLastError());
  230. goto end;
  231. }
  232. //
  233. // spin off threads in suspended mode
  234. //
  235. for ( dwIndex = 0; dwIndex < m_dwNumThreads; dwIndex++ )
  236. {
  237. pHandles[dwIndex] = CreateThread( NULL, /* no security descriptor */
  238. 0, /* default stack size */
  239. SpinNewThread,
  240. this, /* thread parameters */
  241. CREATE_SUSPENDED , /* suspended mode*/
  242. NULL /* not getting thread id */
  243. );
  244. if ( pHandles[dwIndex] == NULL ) // thread creation failed
  245. {
  246. hr = HRESULT_FROM_WIN32(GetLastError());
  247. fCreateThreadFailed = TRUE;
  248. break;
  249. }
  250. }
  251. //
  252. // we need dwCount b/c CreateThread may fail,
  253. // then we just need to loop through dwCount
  254. // threads
  255. //
  256. dwCount = dwIndex;
  257. if ( fCreateThreadFailed == TRUE )
  258. {
  259. for ( dwIndex = 0; dwIndex < dwCount; dwIndex++)
  260. {
  261. TerminateThread( pHandles[dwIndex],
  262. GetLastError()
  263. );
  264. CloseHandle( pHandles[dwIndex]);
  265. }
  266. goto end;
  267. }
  268. //
  269. // Set our own event handler for CTRL_C_EVENT,
  270. // CTRL_BREAK_EVENT, CTRL_LOGOFF_EVENT,
  271. // CTRL_SHUTDOWN_EVENT if verbosity > 0
  272. // else we don't debug
  273. //
  274. if ( m_chVerbosity > 0 )
  275. {
  276. SetConsoleCtrlHandler( ConsoleCtrlHandler,
  277. TRUE
  278. );
  279. }
  280. //
  281. // resume thread
  282. //
  283. for ( dwIndex = 0; dwIndex < dwCount; dwIndex++)
  284. {
  285. ResumeThread( pHandles[dwIndex]);
  286. }
  287. //
  288. // wait for all threads to exit
  289. //
  290. WaitForMultipleObjects( dwCount, // number of handles in array
  291. pHandles, // object-handle array
  292. TRUE, // wait option
  293. INFINITE // time-out interval
  294. );
  295. //
  296. // check for Ctrl+C, Ctrl+Break, etc
  297. //
  298. if ( CONSOLE_HANDLER_VAR::g_HAS_CONSOLE_EVENT_OCCURED == TRUE )
  299. {
  300. ExitProcess(CONSOLE_HANDLER_VAR::g_PROCESS_EXIT_CODE);
  301. }
  302. //
  303. // Turn back the default handler for CTRL_C_EVENT,
  304. // CTRL_BREAK_EVENT, CTRL_LOGOFF_EVENT,
  305. // CTRL_SHUTDOWN_EVENT
  306. //
  307. if ( m_chVerbosity > 0 )
  308. {
  309. SetConsoleCtrlHandler( ConsoleCtrlHandler,
  310. FALSE
  311. );
  312. }
  313. for ( dwIndex = 0; dwIndex < dwCount; dwIndex++)
  314. {
  315. CloseHandle(pHandles[dwIndex]);
  316. }
  317. end:
  318. delete [] pHandles;
  319. return hr;
  320. }
  321. DWORD WINAPI
  322. w3wpList::SpinNewThread( LPVOID lpParam )
  323. /*++
  324. Routine Description:
  325. static Thread function
  326. Arguments:
  327. None
  328. Return Value:
  329. DWORD
  330. --*/
  331. {
  332. w3wpList* pw3wpList = (w3wpList*) lpParam;
  333. pw3wpList->EnumAllWPThread();
  334. return TRUE;
  335. }
  336. VOID
  337. w3wpList::EnumAllWPThread()
  338. /*++
  339. Routine Description:
  340. Each thread goes through the PID array
  341. and processess specific process.
  342. So, thread n will process the first
  343. available PID and then PIDs at an
  344. increment of NumOfThreads positions
  345. in the array
  346. Arguments:
  347. None
  348. Return Value:
  349. None
  350. --*/
  351. {
  352. //
  353. // get the first available index to start with
  354. //
  355. DWORD dwStartIndex = InterlockedIncrement(&m_startingIndex);
  356. //
  357. // since m_startingIndex is initialized to zero and we want to start
  358. // from index 0
  359. //
  360. dwStartIndex--;
  361. //
  362. // walk throught the array of PIDs and
  363. // call DoWork on each of them. DoWork
  364. // creates ProcessDetails obj for
  365. // each PID and gets the requests
  366. // if it were a worker process
  367. //
  368. for ( DWORD i = dwStartIndex;
  369. i < m_dwNumProcessId;
  370. i += m_dwNumThreads)
  371. {
  372. //
  373. // continue until we find the PID
  374. // of our interest. Only interesting
  375. // if lInputPID != -1, i.e were looking
  376. // at the app pool id
  377. //
  378. if ( (m_dwTargetPID != -1 ) &&
  379. (m_dwTargetPID != m_pdwProcessId[i])
  380. )
  381. {
  382. continue;
  383. }
  384. DoWork( m_pdwProcessId[i] );
  385. if (m_dwTargetPID == m_pdwProcessId[i])
  386. {
  387. break;
  388. }
  389. }// end for
  390. }
  391. VOID
  392. w3wpList::DoWork( IN DWORD dwPID )
  393. /*++
  394. Routine Description:
  395. Ccreates ProcessDetails obj for
  396. each PID and gets the requests
  397. if it were a worker process.
  398. It then adds that obj to the list
  399. Arguments:
  400. dwPID -- PID of the process
  401. Return Value:
  402. None
  403. --*/
  404. {
  405. HRESULT hr;
  406. W3WPLIST_NODE* pW3wpListNode = NULL;
  407. //
  408. // create new Node for the list
  409. //
  410. pW3wpListNode = new W3WPLIST_NODE();
  411. if ( pW3wpListNode == NULL )
  412. {
  413. goto end;
  414. }
  415. //
  416. // Initialize the ProcessDetails obj
  417. // in the node
  418. //
  419. pW3wpListNode->m_wpDetails.Init( dwPID,
  420. m_chVerbosity,
  421. m_fIsListMode
  422. );
  423. //
  424. // return value is S_OK if this was a worker process,
  425. // else it is S_FALSE
  426. //
  427. hr = pW3wpListNode->m_wpDetails.GetProcessDetails(m_pszTargetAppPoolId);
  428. if ( hr == S_FALSE )
  429. {
  430. goto cleanup;
  431. }
  432. //
  433. // It was a worker process, add the node to
  434. // the list
  435. //
  436. EnterCriticalSection( &m_CriticalSection );
  437. InsertTailList( &m_listHead,
  438. &(pW3wpListNode->m_listEntry)
  439. );
  440. LeaveCriticalSection( &m_CriticalSection );
  441. goto end;
  442. cleanup:
  443. pW3wpListNode->m_wpDetails.Terminate();
  444. delete pW3wpListNode;
  445. end:
  446. return;
  447. }
  448. HRESULT
  449. w3wpList::EnableDebugPrivilege()
  450. /*++
  451. Routine Description:
  452. Changes the privilege of the current process
  453. so that it can debug other processes.
  454. Arguments:
  455. None
  456. Return Value:
  457. HRESULT hr -- S_FALSE, if exe name does not match
  458. S_OK if name matched and other funcitons
  459. called from within also passed
  460. Error code: if anything else failed
  461. --*/
  462. {
  463. HRESULT Status = S_OK;
  464. HANDLE Token;
  465. PTOKEN_PRIVILEGES NewPrivileges;
  466. BYTE OldPriv[1024];
  467. ULONG cbNeeded;
  468. LUID LuidPrivilege;
  469. //
  470. // Make sure we have access to adjust and to get the
  471. // old token privileges
  472. //
  473. if (!OpenProcessToken(GetCurrentProcess(),
  474. TOKEN_ADJUST_PRIVILEGES | TOKEN_QUERY,
  475. &Token)
  476. )
  477. {
  478. Status = GetLastError();
  479. goto EH_Exit;
  480. }
  481. cbNeeded = 0;
  482. //
  483. // Initialize the privilege adjustment structure
  484. //
  485. LookupPrivilegeValue(NULL, SE_DEBUG_NAME, &LuidPrivilege);
  486. NewPrivileges = (PTOKEN_PRIVILEGES)
  487. calloc(1, sizeof(TOKEN_PRIVILEGES) +
  488. (1 - ANYSIZE_ARRAY) * sizeof(LUID_AND_ATTRIBUTES));
  489. if (NewPrivileges == NULL)
  490. {
  491. Status = E_OUTOFMEMORY;
  492. goto EH_Token;
  493. }
  494. //
  495. // set new privilege
  496. //
  497. NewPrivileges->PrivilegeCount = 1;
  498. NewPrivileges->Privileges[0].Luid = LuidPrivilege;
  499. NewPrivileges->Privileges[0].Attributes = SE_PRIVILEGE_ENABLED;
  500. //
  501. // Enable the privilege
  502. //
  503. if (!AdjustTokenPrivileges( Token,
  504. FALSE,
  505. NewPrivileges,
  506. sizeof(OldPriv),
  507. (PTOKEN_PRIVILEGES)OldPriv,
  508. &cbNeeded )
  509. )
  510. {
  511. //
  512. // If the stack was too small to hold the privileges
  513. // then allocate off the heap
  514. //
  515. if ( GetLastError() == ERROR_INSUFFICIENT_BUFFER )
  516. {
  517. PBYTE pbOldPriv;
  518. BOOL Adjusted;
  519. pbOldPriv = (PUCHAR)calloc(1, cbNeeded);
  520. if ( pbOldPriv == NULL )
  521. {
  522. Status = E_OUTOFMEMORY;
  523. goto EH_NewPriv;
  524. }
  525. Adjusted = AdjustTokenPrivileges( Token,
  526. FALSE,
  527. NewPrivileges,
  528. cbNeeded,
  529. (PTOKEN_PRIVILEGES)pbOldPriv,
  530. &cbNeeded );
  531. free(pbOldPriv);
  532. if ( !Adjusted )
  533. {
  534. Status = GetLastError();
  535. }
  536. }
  537. }
  538. EH_NewPriv:
  539. free(NewPrivileges);
  540. EH_Token:
  541. CloseHandle(Token);
  542. EH_Exit:
  543. return Status;
  544. }
  545. VOID
  546. w3wpList::OutputRequests()
  547. /*++
  548. Routine Description:
  549. Outputs the information for each
  550. of the ProcessDetails obj
  551. Arguments:
  552. None
  553. Return Value:
  554. None
  555. --*/
  556. {
  557. PLIST_ENTRY pListEntry;
  558. W3WPLIST_NODE* pListNode;
  559. for ( pListEntry = m_listHead.Flink;
  560. pListEntry != &m_listHead;
  561. pListEntry = pListEntry->Flink
  562. )
  563. {
  564. pListNode = CONTAINING_RECORD( pListEntry,
  565. W3WPLIST_NODE,
  566. m_listEntry
  567. );
  568. DBG_ASSERT (pListNode->CheckSignature());
  569. pListNode->m_wpDetails.DumpRequests();
  570. }
  571. }
  572. BOOL
  573. w3wpList::ListEmpty()
  574. /*++
  575. Routine Description:
  576. Returns TRUE if the list of
  577. ProcessDetails obj is empty
  578. Arguments:
  579. None
  580. Return Value:
  581. BOOL
  582. --*/
  583. {
  584. return IsListEmpty(&m_listHead);
  585. }
  586. BOOL WINAPI
  587. w3wpList::ConsoleCtrlHandler( DWORD dwCtrlType )
  588. {
  589. BOOL fReturnValue = TRUE;
  590. switch (dwCtrlType)
  591. {
  592. // Handle the CTRL+C signal.
  593. case CTRL_C_EVENT:
  594. case CTRL_BREAK_EVENT:
  595. case CTRL_LOGOFF_EVENT:
  596. case CTRL_SHUTDOWN_EVENT:
  597. {
  598. CONSOLE_HANDLER_VAR::g_HAS_CONSOLE_EVENT_OCCURED = TRUE;
  599. break;
  600. }
  601. default:
  602. {
  603. CONSOLE_HANDLER_VAR::g_HAS_CONSOLE_EVENT_OCCURED = FALSE;
  604. fReturnValue = FALSE;
  605. }
  606. }
  607. return fReturnValue;
  608. }
  609. int __cdecl wmain(DWORD argc, WCHAR ** argv)
  610. {
  611. #define COL_WIDTH 30
  612. WCHAR pszIndent[] = { L" " };
  613. w3wpList w3wplstMyList;
  614. BOOL fIsListMode = FALSE;
  615. WCHAR* pszInputAppPoolId = NULL;
  616. UCHAR chInputVerbosity = 0;
  617. LONG lInputPID = -1;
  618. HRESULT hr;
  619. if ( argc <= 1 ) // no input args; list mode
  620. {
  621. fIsListMode = TRUE;
  622. }
  623. else if ( argc == 2 ) // better be /?, else it's error
  624. {
  625. if ( _wcsicmp (argv[1], L"/?") == 0 ) // help
  626. {
  627. wprintf (L"Copyright (c) Microsoft Corporation. All rights reserved.\n\n\n");
  628. wprintf (L"%s\n%s\n%s\n\n",
  629. L"Description: Use this tool to obtain worker process information, determine which",
  630. L"worker process is assigned to a given application pool and show the requests",
  631. L"that are queued in the worker process.");
  632. wprintf (L"Syntax: w3wplist [{/p | /a} <identifier> [<level of details>]]\n\n");
  633. wprintf (L"Parameters:\n");
  634. wprintf ( L"%-*s%s\n\n",
  635. COL_WIDTH,
  636. L"Value",
  637. L"Description");
  638. wprintf ( L"%-*s%s\n%-*s%s\n",
  639. COL_WIDTH,
  640. L"/p",
  641. L"Indicates that the <identifier> is a worker",
  642. COL_WIDTH,
  643. pszIndent,
  644. L"process PID number."
  645. );
  646. wprintf ( L"%-*s%s\n%-*s%s\n\n",
  647. COL_WIDTH,
  648. L"/a",
  649. L"Indicates that the <identifier> is an application",
  650. COL_WIDTH,
  651. pszIndent,
  652. L"pool identifier."
  653. );
  654. wprintf ( L"%-*s\n",
  655. COL_WIDTH,
  656. L"<identifier>"
  657. );
  658. wprintf ( L"%-*s%s\n%-*s%s\n%-*s%s\n",
  659. COL_WIDTH,
  660. L"application pool identifier",
  661. L"Displays information associated with all active ",
  662. COL_WIDTH,
  663. pszIndent,
  664. L"worker processes for the application pool",
  665. COL_WIDTH,
  666. pszIndent,
  667. L"specified."
  668. );
  669. wprintf ( L"%-*s%s\n%-*s%s\n\n",
  670. COL_WIDTH,
  671. L"worker process PID",
  672. L"Displays information associated with the worker",
  673. COL_WIDTH,
  674. pszIndent,
  675. L"process specified."
  676. );
  677. wprintf ( L"%-*s%s\n",
  678. COL_WIDTH,
  679. L"<level of details>",
  680. L"Verbosity levels are cumulative"
  681. );
  682. wprintf ( L"%-*s%s\n%-*s%s\n%-*s%s\n%-*s%s\n",
  683. COL_WIDTH,
  684. L"/v or /v0",
  685. L"Displays the worker process PID, the application",
  686. COL_WIDTH,
  687. pszIndent,
  688. L"pool identifier, the application pool friendly-",
  689. COL_WIDTH,
  690. pszIndent,
  691. L"name, and the total number of requests that have",
  692. COL_WIDTH,
  693. pszIndent,
  694. L"been processed."
  695. );
  696. wprintf ( L"%-*s%s\n%-*s%s\n",
  697. COL_WIDTH,
  698. L"/v1",
  699. L"Adds the Universal Resource Identifier, host name,",
  700. COL_WIDTH,
  701. pszIndent,
  702. L"and the HTTP verb."
  703. );
  704. wprintf ( L"%-*s%s\n",
  705. COL_WIDTH,
  706. L"/v2",
  707. L"Adds the URI query and the protocol version."
  708. );
  709. wprintf ( L"%-*s%s\n%-*s%s\n",
  710. COL_WIDTH,
  711. L"/v3",
  712. L"Adds the time, date, client-ip, and the referer,",
  713. COL_WIDTH,
  714. pszIndent,
  715. L"user-agent, and cookie headers if available."
  716. );
  717. wprintf ( L"%-*s%s\n%-*s%s\n\n",
  718. COL_WIDTH,
  719. L"/v4",
  720. L"Adds the remaining available headers for the ",
  721. COL_WIDTH,
  722. pszIndent,
  723. L"current request."
  724. );
  725. wprintf ( L"%s\n%s\n%s\n%s\n%s\n%s\n",
  726. L"Examples:",
  727. L" C:\\>w3wplist",
  728. L" C:\\>w3wplist /a app_pool_014",
  729. L" C:\\>w3wplist /p 4852",
  730. L" C:\\>w3wplist /a app_pool_014 /v",
  731. L" C:\\>w3wplist /p 4852 /v1"
  732. );
  733. // MORE STUFF GOES HERE
  734. goto end;
  735. }
  736. else if ( _wcsicmp (argv[1], L"/p") == 0 )
  737. {
  738. wprintf (L"%s\n%s\n",
  739. L"No worker process PID (W3wp.exe) was specified. Use Windows Task Manager to",
  740. L"obtain a valid W3wp.exe PID number.");
  741. goto end;
  742. }
  743. else if ( _wcsicmp (argv[1], L"/a") == 0 )
  744. {
  745. wprintf (L"%s\n%s\n",
  746. L"No application pool identifier was specified. Search in Metabase.xml to obtain",
  747. L"a valid application pool identifier.");
  748. goto end;
  749. }
  750. else // invalid syntax
  751. {
  752. wprintf (L"Invalid syntax. Type w3wplist /? for help.\n");
  753. goto end;
  754. }
  755. }
  756. else if (argc == 4)
  757. {
  758. if ( (_wcsicmp(argv[3], L"/v") == 0) ||
  759. (_wcsicmp(argv[3], L"/v0") == 0 )
  760. )
  761. {
  762. chInputVerbosity = 0;
  763. }
  764. else if (_wcsicmp(argv[3], L"/v1") == 0)
  765. {
  766. chInputVerbosity = 1;
  767. }
  768. else if (_wcsicmp(argv[3], L"/v2") == 0)
  769. {
  770. chInputVerbosity = 2;
  771. }
  772. else if (_wcsicmp(argv[3], L"/v3") == 0)
  773. {
  774. chInputVerbosity = 3;
  775. }
  776. else if (_wcsicmp(argv[3], L"/v4") == 0)
  777. {
  778. chInputVerbosity = 4;
  779. }
  780. else if ( argc != 3 )
  781. {
  782. wprintf (L"Invalid syntax. Type w3wplist /? for help.\n");
  783. goto end;
  784. }
  785. }
  786. if ( (argc == 3 ) ||
  787. (argc == 4)
  788. )
  789. {
  790. // default verbosity of 0
  791. if ( _wcsicmp (argv[1], L"/p") == 0 )
  792. {
  793. lInputPID = wcstol(argv[2], L'\0', 10);
  794. }
  795. else if ( _wcsicmp (argv[1], L"/a") == 0 )
  796. {
  797. pszInputAppPoolId = argv[2];
  798. }
  799. }
  800. //
  801. // initialize the object
  802. //
  803. hr = w3wplstMyList.Init( chInputVerbosity,
  804. fIsListMode,
  805. pszInputAppPoolId,
  806. lInputPID );
  807. if ( FAILED (hr) )
  808. {
  809. goto error;
  810. }
  811. hr = w3wplstMyList.GetProcesses();
  812. if ( FAILED (hr) )
  813. {
  814. goto error;
  815. }
  816. //
  817. // if list is empty, it means that either the input
  818. // PID number was not a worker process or was invalid,
  819. // or the input app pool id was invalid
  820. //
  821. if ( w3wplstMyList.ListEmpty() )
  822. {
  823. // some message of not found
  824. if ( lInputPID != -1 ) // /p switch was input
  825. {
  826. wprintf( L"%s\n%s\n%s\n",
  827. L"The worker process PID number (W3wp.exe) is not valid or is not associated with",
  828. L"a W3wp.exe process. Use Windows Task Manager to obtain a valid W3wp.exe PID",
  829. L"number." );
  830. }
  831. else if ( pszInputAppPoolId != NULL ) // /a switch was input
  832. {
  833. wprintf( L"%s\n%s\n",
  834. L"The application pool identifier is not valid or does not exist. Search in",
  835. L"Metabase.xml to obtain a valid application pool identifier." );
  836. }
  837. }
  838. // print out requests
  839. w3wplstMyList.OutputRequests();
  840. // deallocate memory
  841. w3wplstMyList.DestroyObject();
  842. goto end;
  843. error:
  844. // message of error
  845. wprintf ( L"Error occured. Error code : %d\n",
  846. HRESULT_CODE(hr)
  847. );
  848. end:
  849. return 0;
  850. }