Reactos
at master 641 lines 18 kB view raw
1/* 2 * PROJECT: ReactOS Drivers 3 * LICENSE: BSD - See COPYING.ARM in the top level directory 4 * FILE: drivers/sac/driver/concmd.c 5 * PURPOSE: Driver for the Server Administration Console (SAC) for EMS 6 * PROGRAMMERS: ReactOS Portable Systems Group 7 */ 8 9/* INCLUDES *******************************************************************/ 10 11#include "sacdrv.h" 12 13#include <ndk/exfuncs.h> 14 15/* GLOBALS ********************************************************************/ 16 17PVOID GlobalBuffer; 18ULONG GlobalBufferSize; 19 20/* FUNCTIONS ******************************************************************/ 21 22NTSTATUS 23DoChannelListCommand( 24 VOID 25 ) 26{ 27 return STATUS_NOT_IMPLEMENTED; 28} 29 30NTSTATUS 31DoChannelCloseByNameCommand( 32 IN PCHAR Count 33 ) 34{ 35 return STATUS_NOT_IMPLEMENTED; 36} 37 38NTSTATUS 39DoChannelCloseByIndexCommand( 40 IN ULONG ChannelIndex 41 ) 42{ 43 return STATUS_NOT_IMPLEMENTED; 44} 45 46NTSTATUS 47DoChannelSwitchByNameCommand( 48 IN PCHAR Count 49 ) 50{ 51 return STATUS_NOT_IMPLEMENTED; 52} 53 54NTSTATUS 55DoChannelSwitchByIndexCommand( 56 IN ULONG ChannelIndex 57 ) 58{ 59 return STATUS_NOT_IMPLEMENTED; 60} 61 62typedef struct _SAC_SYSTEM_INFORMATION 63{ 64 SYSTEM_BASIC_INFORMATION BasicInfo; 65 SYSTEM_TIMEOFDAY_INFORMATION TimeInfo; 66 SYSTEM_FILECACHE_INFORMATION CacheInfo; 67 SYSTEM_PERFORMANCE_INFORMATION PerfInfo; 68 ULONG RemainingSize; 69 ULONG ProcessDataOffset; 70 // SYSTEM_PAGEFILE_INFORMATION PageFileInfo; 71 // SYSTEM_PROCESS_INFORMATION ProcessInfo; 72} SAC_SYSTEM_INFORMATION, *PSAC_SYSTEM_INFORMATION; 73 74NTSTATUS 75NTAPI 76GetTListInfo(IN PSAC_SYSTEM_INFORMATION SacInfo, 77 IN ULONG InputSize, 78 OUT PULONG TotalSize) 79{ 80 NTSTATUS Status; 81 ULONG BufferLength, ReturnLength, RemainingSize; 82 PSYSTEM_PAGEFILE_INFORMATION PageFileInfo; 83 PSYSTEM_PROCESS_INFORMATION ProcessInfo; 84 ULONG_PTR P; 85 SAC_DBG(SAC_DBG_ENTRY_EXIT, "Entering.\n"); 86 87 /* Assume failure */ 88 *TotalSize = 0; 89 90 /* Bail out if the buffer is way too small */ 91 if (InputSize < 4) 92 { 93 SAC_DBG(SAC_DBG_ENTRY_EXIT, "Exiting, no memory.\n"); 94 return STATUS_NO_MEMORY; 95 } 96 97 /* Make sure it's at least big enough to hold the static structure */ 98 BufferLength = InputSize - sizeof(SAC_SYSTEM_INFORMATION); 99 if (InputSize < sizeof(SAC_SYSTEM_INFORMATION)) 100 { 101 SAC_DBG(SAC_DBG_ENTRY_EXIT, "Exiting, no memory (2).\n"); 102 return STATUS_NO_MEMORY; 103 } 104 105 /* Query the time */ 106 Status = ZwQuerySystemInformation(SystemTimeOfDayInformation, 107 &SacInfo->TimeInfo, 108 sizeof(SacInfo->TimeInfo), 109 NULL); 110 if (!NT_SUCCESS(Status)) 111 { 112 SAC_DBG(SAC_DBG_ENTRY_EXIT, "Exiting, error.\n"); 113 return Status; 114 } 115 116 /* Query basic information */ 117 Status = ZwQuerySystemInformation(SystemBasicInformation, 118 &SacInfo->BasicInfo, 119 sizeof(SacInfo->BasicInfo), 120 NULL); 121 if (!NT_SUCCESS(Status)) 122 { 123 SAC_DBG(SAC_DBG_ENTRY_EXIT, "Exiting, error (2).\n"); 124 return Status; 125 } 126 127 /* Now query the pagefile information, which comes right after */ 128 P = (ULONG_PTR)(SacInfo + 1); 129 PageFileInfo = (PSYSTEM_PAGEFILE_INFORMATION)P; 130 Status = ZwQuerySystemInformation(SystemPageFileInformation, 131 PageFileInfo, 132 BufferLength, 133 &ReturnLength); 134 if (!NT_SUCCESS(Status) || !(ReturnLength)) 135 { 136 /* We failed -- is it because our buffer was too small? */ 137 if (BufferLength < ReturnLength) 138 { 139 /* Bail out */ 140 SAC_DBG(SAC_DBG_ENTRY_EXIT, "Exiting, no memory(5).\n"); 141 return STATUS_NO_MEMORY; 142 } 143 144 /* Some other reason, assume the buffer is now full */ 145 SacInfo->RemainingSize = 0; 146 } 147 else 148 { 149 /* This is the leftover data */ 150 SacInfo->RemainingSize = InputSize - BufferLength; 151 152 /* This much has now been consumed, and where we are now */ 153 BufferLength -= ReturnLength; 154 P += ReturnLength; 155 156 /* Are we out of memory? */ 157 if ((LONG)BufferLength < 0) 158 { 159 /* Bail out */ 160 SAC_DBG(SAC_DBG_ENTRY_EXIT, "Exiting, no memory(3).\n"); 161 return STATUS_NO_MEMORY; 162 } 163 164 /* All good, loop the pagefile data now */ 165 while (TRUE) 166 { 167 /* Is the pagefile name too big to fit? */ 168 if (PageFileInfo->PageFileName.Length > (LONG)BufferLength) 169 { 170 /* Bail out */ 171 SAC_DBG(SAC_DBG_ENTRY_EXIT, "Exiting, error(3).\n"); 172 return STATUS_INFO_LENGTH_MISMATCH; 173 } 174 175 /* Copy the name into our own buffer */ 176 RtlCopyMemory((PVOID)P, 177 PageFileInfo->PageFileName.Buffer, 178 PageFileInfo->PageFileName.Length); 179 PageFileInfo->PageFileName.Buffer = (PWCHAR)P; 180 181 /* Update buffer lengths and offset */ 182 BufferLength -= PageFileInfo->PageFileName.Length; 183 P += PageFileInfo->PageFileName.Length; 184 185 /* Are we out of memory? */ 186 if ((LONG)BufferLength < 0) 187 { 188 /* Bail out */ 189 SAC_DBG(SAC_DBG_ENTRY_EXIT, "Exiting, no memory(4).\n"); 190 return STATUS_NO_MEMORY; 191 } 192 193 /* If this was the only pagefile, break out */ 194 if (!PageFileInfo->NextEntryOffset) break; 195 196 /* Otherwise, move to the next one */ 197 PageFileInfo = (PVOID)((ULONG_PTR)PageFileInfo + 198 PageFileInfo->NextEntryOffset); 199 } 200 } 201 202 /* Next, query the file cache information */ 203 Status = ZwQuerySystemInformation(SystemFileCacheInformation, 204 &SacInfo->CacheInfo, 205 sizeof(SacInfo->CacheInfo), 206 NULL); 207 if (!NT_SUCCESS(Status)) 208 { 209 SAC_DBG(SAC_DBG_ENTRY_EXIT, "Exiting, error (4).\n"); 210 return Status; 211 } 212 213 /* And then the performance information */ 214 Status = ZwQuerySystemInformation(SystemPerformanceInformation, 215 &SacInfo->PerfInfo, 216 sizeof(SacInfo->PerfInfo), 217 NULL); 218 if (!NT_SUCCESS(Status)) 219 { 220 SAC_DBG(SAC_DBG_ENTRY_EXIT, "Exiting, error(5).\n"); 221 return Status; 222 } 223 224 /* Finally, align the buffer to query process and thread information */ 225 P = ALIGN_UP(P, SYSTEM_PROCESS_INFORMATION); 226 RemainingSize = (ULONG_PTR)SacInfo + InputSize - P; 227 228 /* Are we out of memory? */ 229 if ((LONG)RemainingSize < 0) 230 { 231 /* Bail out */ 232 SAC_DBG(SAC_DBG_ENTRY_EXIT, "Exiting, no memory (6).\n"); 233 return STATUS_NO_MEMORY; 234 } 235 236 /* Now query the processes and threads */ 237 ProcessInfo = (PSYSTEM_PROCESS_INFORMATION)P; 238 Status = ZwQuerySystemInformation(SystemProcessInformation, 239 ProcessInfo, 240 RemainingSize, 241 &ReturnLength); 242 if (!NT_SUCCESS(Status)) 243 { 244 SAC_DBG(SAC_DBG_ENTRY_EXIT, "Exiting, error(6).\n"); 245 return Status; 246 } 247 248 /* The first process name will be right after this buffer */ 249 P += ReturnLength; 250 251 /* The caller should look for process info over here */ 252 SacInfo->ProcessDataOffset = InputSize - RemainingSize; 253 254 /* This is how much buffer data we have left -- are we out? */ 255 BufferLength = RemainingSize - ReturnLength; 256 if ((LONG)BufferLength < 0) 257 { 258 /* Bail out */ 259 SAC_DBG(SAC_DBG_ENTRY_EXIT, "Exiting, no memory(7).\n"); 260 return STATUS_NO_MEMORY; 261 } 262 263 /* All good and ready to parse the process and thread list */ 264 while (TRUE) 265 { 266 /* Does the process have a name? */ 267 if (ProcessInfo->ImageName.Buffer) 268 { 269 /* Is the process name too big to fit? */ 270 if ((LONG)BufferLength < ProcessInfo->ImageName.Length) 271 { 272 /* Bail out */ 273 SAC_DBG(SAC_DBG_ENTRY_EXIT, "Exiting, error(7).\n"); 274 return STATUS_INFO_LENGTH_MISMATCH; 275 } 276 277 /* Copy the name into our own buffer */ 278 RtlCopyMemory((PVOID)P, 279 ProcessInfo->ImageName.Buffer, 280 ProcessInfo->ImageName.Length); 281 ProcessInfo->ImageName.Buffer = (PWCHAR)P; 282 283 /* Update buffer lengths and offset */ 284 BufferLength -= ProcessInfo->ImageName.Length; 285 P += ProcessInfo->ImageName.Length; 286 287 /* Are we out of memory? */ 288 if ((LONG)BufferLength < 0) 289 { 290 /* Bail out */ 291 SAC_DBG(SAC_DBG_ENTRY_EXIT, "Exiting, no memory(8).\n"); 292 return STATUS_NO_MEMORY; 293 } 294 } 295 296 /* If this was the only process, break out */ 297 if (!ProcessInfo->NextEntryOffset) break; 298 299 /* Otherwise, move to the next one */ 300 ProcessInfo = (PVOID)((ULONG_PTR)ProcessInfo + 301 ProcessInfo->NextEntryOffset); 302 } 303 304 /* All done! */ 305 SAC_DBG(SAC_DBG_ENTRY_EXIT, "Exiting.\n"); 306 *TotalSize = InputSize - BufferLength; 307 return STATUS_SUCCESS; 308} 309 310VOID 311NTAPI 312PrintTListInfo(IN PSAC_SYSTEM_INFORMATION SacInfo) 313{ 314 SAC_DBG(SAC_DBG_ENTRY_EXIT, "Testing: %d %d %I64d\n", 315 SacInfo->BasicInfo.NumberOfPhysicalPages, 316 SacInfo->PerfInfo.AvailablePages, 317 SacInfo->TimeInfo.BootTime); 318} 319 320VOID 321NTAPI 322PutMore(OUT PBOOLEAN ScreenFull) 323{ 324 *ScreenFull = FALSE; 325} 326 327BOOLEAN 328RetrieveIpAddressFromString( 329 IN PWCHAR IpString, 330 OUT PULONG IpAddress 331 ) 332{ 333 return FALSE; 334} 335 336NTSTATUS 337CallQueryIPIOCTL( 338 IN HANDLE DriverHandle, 339 IN PVOID DriverObject, 340 IN HANDLE WaitEvent, 341 IN PIO_STATUS_BLOCK IoStatusBlock, 342 IN PVOID InputBuffer, 343 IN ULONG InputBufferLength, 344 IN PVOID OutputBuffer, 345 IN ULONG OutputBufferLength, 346 IN BOOLEAN PrintMessage, 347 OUT PBOOLEAN MessagePrinted 348 ) 349{ 350 return STATUS_NOT_IMPLEMENTED; 351} 352 353VOID 354NTAPI 355DoRebootCommand(IN BOOLEAN Reboot) 356{ 357 LARGE_INTEGER Timeout, TickCount; 358 NTSTATUS Status; 359 KEVENT Event; 360 SAC_DBG(SAC_DBG_ENTRY_EXIT, "SAC DoRebootCommand: Entering.\n"); 361 362 /* Get the current time now, and setup a timeout in 1 second */ 363 KeQueryTickCount(&TickCount); 364 Timeout.QuadPart = TickCount.QuadPart / (10000000 / KeQueryTimeIncrement()); 365 366 /* Check if the timeout is small enough */ 367 if (Timeout.QuadPart < 60 ) 368 { 369 /* Show the prompt */ 370 ConMgrSimpleEventMessage(Reboot ? 371 SAC_RESTART_PROMPT : SAC_SHUTDOWN_PROMPT, 372 TRUE); 373 374 /* Do the wait */ 375 KeInitializeEvent(&Event, SynchronizationEvent, 0); 376 Timeout.QuadPart = -10000000 * (60 - Timeout.LowPart); 377 KeWaitForSingleObject(&Event, Executive, KernelMode, FALSE, &Timeout); 378 } 379 380 /* Do a shutdown or a reboot, based on the request */ 381 Status = NtShutdownSystem(Reboot ? ShutdownReboot : ShutdownPowerOff); 382 383 /* Check if anyone in the command channel already allocated this */ 384 if (!GlobalBuffer) 385 { 386 /* Allocate it */ 387 GlobalBuffer = SacAllocatePool(PAGE_SIZE, GLOBAL_BLOCK_TAG); 388 if (!GlobalBuffer) 389 { 390 /* We need the global buffer, bail out without it*/ 391 SacPutSimpleMessage(SAC_OUT_OF_MEMORY_PROMPT); 392 SAC_DBG(SAC_DBG_ENTRY_EXIT, "SAC DoRebootCommand: Exiting (1).\n"); 393 return; 394 } 395 396 /* Set the size of the buffer */ 397 GlobalBufferSize = PAGE_SIZE; 398 } 399 400 /* We came back from a reboot, this doesn't make sense, tell the user */ 401 SacPutSimpleMessage(Reboot ? SAC_RESTART_FAIL_PROMPT : SAC_SHUTDOWN_FAIL_PROMPT); 402 swprintf(GlobalBuffer, GetMessage(SAC_FAIL_PROMPT), Status); 403 SacPutString(GlobalBuffer); 404 SAC_DBG(SAC_DBG_ENTRY_EXIT, "SAC DoRebootCommand: Exiting.\n"); 405} 406 407VOID 408NTAPI 409DoFullInfoCommand(VOID) 410{ 411 /* Flip the flag */ 412 GlobalDoThreads = !GlobalDoThreads; 413 414 /* Print out the new state */ 415 SacPutSimpleMessage(GlobalDoThreads ? 8 : 7); 416} 417 418VOID 419NTAPI 420DoPagingCommand(VOID) 421{ 422 /* Flip the flag */ 423 GlobalPagingNeeded = !GlobalPagingNeeded; 424 425 /* Print out the new state */ 426 SacPutSimpleMessage(GlobalPagingNeeded ? 10 : 9); 427} 428 429VOID 430NTAPI 431DoSetTimeCommand(IN PCHAR InputTime) 432{ 433 SAC_DBG(SAC_DBG_ENTRY_EXIT, "Entering\n"); 434} 435 436VOID 437NTAPI 438DoKillCommand(IN PCHAR KillString) 439{ 440 SAC_DBG(SAC_DBG_ENTRY_EXIT, "Entering\n"); 441} 442 443VOID 444NTAPI 445DoLowerPriorityCommand(IN PCHAR PrioString) 446{ 447 SAC_DBG(SAC_DBG_ENTRY_EXIT, "Entering\n"); 448} 449 450VOID 451NTAPI 452DoRaisePriorityCommand(IN PCHAR PrioString) 453{ 454 SAC_DBG(SAC_DBG_ENTRY_EXIT, "Entering\n"); 455} 456 457VOID 458NTAPI 459DoLimitMemoryCommand(IN PCHAR LimitString) 460{ 461 SAC_DBG(SAC_DBG_ENTRY_EXIT, "Entering\n"); 462} 463 464VOID 465NTAPI 466DoCrashCommand(VOID) 467{ 468 SAC_DBG(SAC_DBG_ENTRY_EXIT, "SAC DoCrashCommand: Entering.\n"); 469 470 /* Crash the machine */ 471 KeBugCheckEx(MANUALLY_INITIATED_CRASH, 0, 0, 0, 0); 472 __debugbreak(); 473} 474 475VOID 476NTAPI 477DoMachineInformationCommand(VOID) 478{ 479 SAC_DBG(SAC_DBG_ENTRY_EXIT, "Entering\n"); 480} 481 482VOID 483NTAPI 484DoChannelCommand(IN PCHAR ChannelString) 485{ 486 SAC_DBG(SAC_DBG_ENTRY_EXIT, "Entering\n"); 487} 488 489VOID 490NTAPI 491DoCmdCommand(IN PCHAR InputString) 492{ 493 SAC_DBG(SAC_DBG_ENTRY_EXIT, "Entering\n"); 494} 495 496VOID 497NTAPI 498DoLockCommand(VOID) 499{ 500 SAC_DBG(SAC_DBG_ENTRY_EXIT, "Entering\n"); 501} 502 503FORCEINLINE 504BOOLEAN 505PrintHelpMessage(IN ULONG MessageId, 506 IN OUT PULONG Count) 507{ 508 BOOLEAN ScreenFull; 509 ULONG NewCount; 510 511 /* Get the amount of lines this message will take */ 512 NewCount = GetMessageLineCount(MessageId); 513 if ((NewCount + *Count) > SAC_VTUTF8_ROW_HEIGHT) 514 { 515 /* We are going to overflow the screen, wait for input */ 516 PutMore(&ScreenFull); 517 if (ScreenFull) return FALSE; 518 *Count = 0; 519 } 520 521 /* Print out the message and update the amount of lines printed */ 522 SacPutSimpleMessage(MessageId); 523 *Count += NewCount; 524 return TRUE; 525} 526 527VOID 528NTAPI 529DoHelpCommand(VOID) 530{ 531 ULONG Count = 0; 532 533 /* Print out all the help messages */ 534 if (!PrintHelpMessage(112, &Count)) return; 535 if (!PrintHelpMessage(12, &Count)) return; 536 if (!PrintHelpMessage(13, &Count)) return; 537 if (!PrintHelpMessage(14, &Count)) return; 538 if (!PrintHelpMessage(15, &Count)) return; 539 if (!PrintHelpMessage(16, &Count)) return; 540 if (!PrintHelpMessage(31, &Count)) return; 541 if (!PrintHelpMessage(18, &Count)) return; 542 if (!PrintHelpMessage(19, &Count)) return; 543 if (!PrintHelpMessage(32, &Count)) return; 544 if (!PrintHelpMessage(20, &Count)) return; 545 if (!PrintHelpMessage(21, &Count)) return; 546 if (!PrintHelpMessage(22, &Count)) return; 547 if (!PrintHelpMessage(23, &Count)) return; 548 if (!PrintHelpMessage(24, &Count)) return; 549 if (!PrintHelpMessage(25, &Count)) return; 550 if (!PrintHelpMessage(27, &Count)) return; 551 if (!PrintHelpMessage(28, &Count)) return; 552 if (!PrintHelpMessage(29, &Count)) return; 553} 554 555VOID 556NTAPI 557DoGetNetInfo(IN BOOLEAN DoPrint) 558{ 559 SAC_DBG(SAC_DBG_ENTRY_EXIT, "Entering\n"); 560} 561 562VOID 563NTAPI 564DoSetIpAddressCommand(IN PCHAR IpString) 565{ 566 SAC_DBG(SAC_DBG_ENTRY_EXIT, "Entering\n"); 567} 568 569VOID 570NTAPI 571DoTlistCommand(VOID) 572{ 573 NTSTATUS Status; 574 PVOID NewGlobalBuffer; 575 ULONG Size; 576 SAC_DBG(SAC_DBG_ENTRY_EXIT, "SAC DoTlistCommand: Entering.\n"); 577 578 /* Check if a global buffer already exists */ 579 if (!GlobalBuffer) 580 { 581 /* It doesn't, allocate one */ 582 GlobalBuffer = SacAllocatePool(4096, GLOBAL_BLOCK_TAG); 583 if (GlobalBuffer) 584 { 585 /* Remember its current size */ 586 GlobalBufferSize = 4096; 587 } 588 else 589 { 590 /* Out of memory, bail out */ 591 SacPutSimpleMessage(11); 592 SAC_DBG(SAC_DBG_ENTRY_EXIT, "SAC DoTlistCommand: Exiting.\n"); 593 return; 594 } 595 } 596 597 /* Loop as long as the buffer is too small */ 598 while (TRUE) 599 { 600 /* Get the process list */ 601 Status = GetTListInfo(GlobalBuffer, GlobalBufferSize, &Size); 602 if ((Status != STATUS_NO_MEMORY) && 603 (Status != STATUS_INFO_LENGTH_MISMATCH)) 604 { 605 /* It fits! Bail out */ 606 break; 607 } 608 609 /* We need a new bigger buffer */ 610 NewGlobalBuffer = SacAllocatePool(GlobalBufferSize + 4096, 611 GLOBAL_BLOCK_TAG); 612 if (!NewGlobalBuffer) 613 { 614 /* Out of memory, bail out */ 615 SacPutSimpleMessage(11); 616 SAC_DBG(SAC_DBG_ENTRY_EXIT, "SAC DoTlistCommand: Exiting.\n"); 617 return; 618 } 619 620 /* Free the old one, update state */ 621 SacFreePool(GlobalBuffer); 622 GlobalBufferSize += 4096; 623 GlobalBuffer = NewGlobalBuffer; 624 } 625 626 /* Did we get here because we have the whole list? */ 627 if (!NT_SUCCESS(Status)) 628 { 629 /* Nope, print out a failure message */ 630 SacPutSimpleMessage(68); 631 swprintf(GlobalBuffer, GetMessage(48), Status); 632 SacPutString(GlobalBuffer); 633 } 634 else 635 { 636 /* Yep, print out the list */ 637 PrintTListInfo(GlobalBuffer); 638 } 639 640 SAC_DBG(SAC_DBG_ENTRY_EXIT, "SAC DoTlistCommand: Exiting.\n"); 641}