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.

427 lines
14 KiB

  1. #include "precomp.h"
  2. #pragma hdrstop
  3. #define BUFFERSIZE 1024
  4. typedef struct _DEVICEINFO {
  5. BOOL DevNodeStarted;
  6. } DEVICEINFO, *PDEVICEINFO;
  7. BOOL
  8. IsDriverLoaded(
  9. PTSTR ServiceName
  10. )
  11. {
  12. NTSTATUS Status;
  13. BOOL bObjectIsLoaded = FALSE;
  14. UCHAR Buffer[BUFFERSIZE];
  15. UNICODE_STRING UnicodeStringDriver, UnicodeStringServiceName;
  16. OBJECT_ATTRIBUTES Attributes;
  17. HANDLE DirectoryHandle;
  18. POBJECT_DIRECTORY_INFORMATION DirInfo;
  19. POBJECT_NAME_INFORMATION NameInfo;
  20. ULONG Context = 0;
  21. ULONG ReturnedLength;
  22. RtlZeroMemory(Buffer, BUFFERSIZE);
  23. RtlInitUnicodeString(&UnicodeStringServiceName, ServiceName);
  24. RtlInitUnicodeString(&UnicodeStringDriver, TEXT("\\Driver"));
  25. InitializeObjectAttributes(&Attributes,
  26. &UnicodeStringDriver,
  27. OBJ_CASE_INSENSITIVE,
  28. NULL,
  29. NULL
  30. );
  31. Status = NtOpenDirectoryObject(&DirectoryHandle,
  32. DIRECTORY_QUERY,
  33. &Attributes
  34. );
  35. if (!NT_SUCCESS(Status)) {
  36. printf("NtOpenDirectoryObject failed with 0x%X\n", Status);
  37. goto clean0;
  38. }
  39. //
  40. // Get the actual name of the object directory object.
  41. //
  42. NameInfo = (POBJECT_NAME_INFORMATION)&Buffer[0];
  43. if (!NT_SUCCESS(Status = NtQueryObject(DirectoryHandle,
  44. ObjectNameInformation,
  45. NameInfo,
  46. BUFFERSIZE,
  47. (PULONG)NULL))) {
  48. printf( "Unexpected error obtaining actual object directory name\n" );
  49. printf( "Error was: %X\n", Status );
  50. goto clean0;
  51. }
  52. //
  53. // Grab the driver objects in chuncks instead of one at a time.
  54. //
  55. for (Status = NtQueryDirectoryObject(DirectoryHandle,
  56. &Buffer,
  57. BUFFERSIZE,
  58. FALSE,
  59. FALSE,
  60. &Context,
  61. &ReturnedLength
  62. );
  63. NT_SUCCESS(Status) && !bObjectIsLoaded;
  64. Status = NtQueryDirectoryObject(DirectoryHandle,
  65. &Buffer,
  66. BUFFERSIZE,
  67. FALSE,
  68. FALSE,
  69. &Context,
  70. &ReturnedLength
  71. )) {
  72. if (!NT_SUCCESS(Status)) {
  73. if (Status != STATUS_NO_MORE_FILES) {
  74. printf("NtQueryDirectoryObject failed with 0x%X\n", Status);
  75. }
  76. break;
  77. }
  78. DirInfo = (POBJECT_DIRECTORY_INFORMATION)&Buffer[0];
  79. while (TRUE) {
  80. //
  81. // Check if there is another record. If there isn't, then get out
  82. // of the loop now.
  83. //
  84. if (DirInfo->Name.Length == 0) {
  85. break;
  86. }
  87. if (RtlCompareUnicodeString(&UnicodeStringServiceName, &(DirInfo->Name), TRUE) == 0) {
  88. bObjectIsLoaded = TRUE;
  89. break;
  90. }
  91. DirInfo = (POBJECT_DIRECTORY_INFORMATION)(((PUCHAR)DirInfo) +
  92. sizeof(OBJECT_DIRECTORY_INFORMATION));
  93. }
  94. RtlZeroMemory(Buffer, BUFFERSIZE);
  95. }
  96. clean0:
  97. NtClose(DirectoryHandle);
  98. return bObjectIsLoaded;
  99. }
  100. BOOL
  101. RestartDevicesUsingService(
  102. LPTSTR ServiceName
  103. )
  104. {
  105. BOOL b = TRUE;
  106. CONFIGRET cr;
  107. DEVNODE DevNode;
  108. BOOL bIsDriverLoaded;
  109. INT count, i;
  110. TCHAR VetoName[512];
  111. ULONG VetoNameLength;
  112. PNP_VETO_TYPE VetoType;
  113. ULONG Status, Problem;
  114. ULONG BufferLen;
  115. OSVERSIONINFO osvi;
  116. PTSTR Buffer = NULL;
  117. PTSTR p;
  118. PDEVICEINFO DeviceInfo = NULL;
  119. printf("Stopping all devices that are using the service %ws\n", ServiceName);
  120. try {
  121. bIsDriverLoaded = IsDriverLoaded(ServiceName);
  122. printf("%ws %ws loaded\n",
  123. ServiceName,
  124. bIsDriverLoaded
  125. ? TEXT("is")
  126. : TEXT("is NOT")
  127. );
  128. //
  129. // If this service is not loaded then we don't need to do anything.
  130. //
  131. if (!bIsDriverLoaded) {
  132. goto clean0;
  133. }
  134. //
  135. // Find out how large a buffer it will take to hold all the devices that
  136. // are using this service.
  137. //
  138. if (((cr = CM_Get_Device_ID_List_Size(&BufferLen,
  139. ServiceName,
  140. CM_GETIDLIST_FILTER_SERVICE
  141. )) != CR_SUCCESS) ||
  142. (BufferLen == 0)) {
  143. if (cr != CR_SUCCESS) {
  144. b = FALSE;
  145. printf("CM_Get_Device_ID_List_Size failed with 0x%X\n", cr);
  146. } else {
  147. printf("There are no devices using this service!\n");
  148. }
  149. goto clean0;
  150. }
  151. Buffer = LocalAlloc(LPTR, BufferLen*sizeof(TCHAR));
  152. if (Buffer == NULL) {
  153. b = FALSE;
  154. goto clean0;
  155. }
  156. //
  157. // Get all of the devices that are using this service.
  158. //
  159. if (CM_Get_Device_ID_List(ServiceName,
  160. Buffer,
  161. BufferLen,
  162. CM_GETIDLIST_FILTER_SERVICE | CM_GETIDLIST_DONOTGENERATE
  163. ) != CR_SUCCESS) {
  164. b = FALSE;
  165. goto clean0;
  166. }
  167. //
  168. // Count up how many devices we are dealing with.
  169. //
  170. count = 0;
  171. for (p = Buffer; *p; p += (lstrlen(p) + 1)) {
  172. count++;
  173. }
  174. if (count == 0) {
  175. printf("There are no devices using this service!\n");
  176. goto clean0;
  177. }
  178. printf("%d devices are using this service\n", count);
  179. //
  180. // Allocate an array of our DEVICEINFO structures so we can keep
  181. // track of the Devnodes and whether a device was started or not
  182. // before we tried to unloade the specified driver.
  183. //
  184. DeviceInfo = LocalAlloc(LPTR, count*sizeof(DEVICEINFO));
  185. if (DeviceInfo == NULL) {
  186. b = FALSE;
  187. goto clean0;
  188. }
  189. //
  190. // Enumerate through all of the devices and stop each one.
  191. //
  192. for (p=Buffer, i=0; *p; p+=(lstrlen(p) + 1),i++) {
  193. printf("Stopping device %ws\n", p);
  194. if ((cr = CM_Locate_DevNode(&DevNode, p, 0)) == CR_SUCCESS) {
  195. if ((CM_Get_DevNode_Status(&Status, &Problem, DevNode, 0) == CR_SUCCESS) &&
  196. (Status & DN_STARTED)) {
  197. DeviceInfo[i].DevNodeStarted = TRUE;
  198. } else {
  199. printf("\tdevice is not started...skipping\n");
  200. DeviceInfo[i].DevNodeStarted = FALSE;
  201. continue;
  202. }
  203. //
  204. // We will pass in the VetoType and VetoName to
  205. // CM_Query_And_Remove_Subtree so we can log while a specific
  206. // device could not be stopped. This will also prevent the
  207. // kernel from poping up a dialog telling the user that the
  208. // device could not be removed.
  209. //
  210. // NOTE: It is important to note that on Whistler we pass in the
  211. // CM_REMOVE_NO_RESTART flag. This ensures that the devnode
  212. // will not be restarted until we call CM_Setup_DevNode to
  213. // restart it at a later time. Without this flag (like in
  214. // Windows 2000) it is possible for the device to restart again
  215. // due to some other program or driver triggering a
  216. // reenumeration.
  217. //
  218. VetoNameLength = sizeof(VetoName)/sizeof(TCHAR);
  219. cr = CM_Query_And_Remove_SubTree(DevNode,
  220. &VetoType,
  221. VetoName,
  222. VetoNameLength,
  223. CM_QUERY_REMOVE_UI_NOT_OK
  224. );
  225. if (cr == CR_REMOVE_VETOED) {
  226. //
  227. // Someone vetoed the removal of this device!
  228. //
  229. // This is here for logging purposes only. If no logging is
  230. // required then there is no need for this check.
  231. //
  232. printf("\tVetoed 0x%X %ws\n", VetoType, VetoName);
  233. }
  234. if (cr != CR_SUCCESS) {
  235. //
  236. // If we couldn't stop one of the devices then we might as well
  237. // stop since we are going to need a reboot.
  238. //
  239. printf("\tFailed with 0x%X!\n", cr);
  240. b = FALSE;
  241. break;
  242. }
  243. } else {
  244. //
  245. // If we couldn't locate one of the devices then there is no need to
  246. // continue through the list since a reboot will be needed.
  247. //
  248. printf("\tCouldn't locate the devnode, error 0x%X!\n", cr);
  249. b = FALSE;
  250. break;
  251. }
  252. }
  253. printf("\n");
  254. if (b) {
  255. bIsDriverLoaded = IsDriverLoaded(ServiceName);
  256. printf("%ws %ws loaded\n\n",
  257. ServiceName,
  258. bIsDriverLoaded
  259. ? TEXT("is")
  260. : TEXT("is NOT")
  261. );
  262. //
  263. // If the driver did not unload, even after we stopped all the
  264. // devices using it, the we need to reboot!
  265. //
  266. if (bIsDriverLoaded) {
  267. b = FALSE;
  268. }
  269. }
  270. //
  271. // At this point we need to enumerate through all the devices once again
  272. // and restart them all. It doesn't matter whether we succeeded or not in
  273. // stopping them all, we still need to restart them.
  274. //
  275. for (p=Buffer, i=0; *p; p+=(lstrlen(p) + 1), i++) {
  276. printf("Starting device %ws\n", p);
  277. if ((cr = CM_Locate_DevNode(&DevNode, p, 0)) == CR_SUCCESS) {
  278. //
  279. // NOTE: For Whistler we will call CM_Setup_DevNode with the
  280. // CM_SETUP_DEVNODE_RESET flag which will clear the
  281. // CM_REMOVE_NO_RESTART flag we set earlier. These two flags
  282. // ensure that the devnode will not get restarted by some other
  283. // program or driver until we want them to.
  284. //
  285. if ((cr = CM_Setup_DevNode(DevNode, CM_SETUP_DEVNODE_READY)) == CR_SUCCESS) {
  286. //
  287. // We successfully restarted the device, lets make sure that it
  288. // started and doesn't have any problems. We will only make
  289. // this check if the device was started before.
  290. //
  291. if (DeviceInfo[i].DevNodeStarted == TRUE) {
  292. if ((CM_Get_DevNode_Status(&Status, &Problem, DevNode, 0) != CR_SUCCESS) ||
  293. !(Status & DN_STARTED)) {
  294. //
  295. // We couldn't get the status of this device, or it did not
  296. // restart properly, so we will need to reboot.
  297. //
  298. printf("\tDevice could not be restarted!\n");
  299. b = FALSE;
  300. }
  301. }
  302. } else {
  303. //
  304. // We couldn't restart this device, so we will need to reboot.
  305. //
  306. printf("\tDevice could not be restarted, error 0x%X!\n", cr);
  307. b = FALSE;
  308. }
  309. } else {
  310. //
  311. // We couldn't locate the devnode to restart it.
  312. //
  313. printf("\tCouldn't locate the devnode, error 0x%X!\n", cr);
  314. b = FALSE;
  315. }
  316. }
  317. printf("%ws %ws loaded\n",
  318. ServiceName,
  319. IsDriverLoaded(ServiceName)
  320. ? TEXT("is")
  321. : TEXT("is NOT")
  322. );
  323. } except(EXCEPTION_EXECUTE_HANDLER) {
  324. Buffer = Buffer;
  325. DeviceInfo = DeviceInfo;
  326. b = FALSE;
  327. }
  328. clean0:
  329. if (Buffer) {
  330. LocalFree(Buffer);
  331. }
  332. if (DeviceInfo) {
  333. LocalFree(DeviceInfo);
  334. }
  335. return b;
  336. }
  337. int
  338. __cdecl
  339. wmain(
  340. IN int argc,
  341. IN char *argv[]
  342. )
  343. {
  344. SC_HANDLE hServiceManager;
  345. ENUM_SERVICE_STATUS ServiceStatus[1000];
  346. DWORD ResumeHandle = 0;
  347. DWORD cbBytesNeeded, cbServicesReturned;
  348. UINT i;
  349. hServiceManager = OpenSCManager(NULL, NULL, SC_MANAGER_ENUMERATE_SERVICE);
  350. if (hServiceManager) {
  351. if (EnumServicesStatus(hServiceManager,
  352. SERVICE_DRIVER,
  353. SERVICE_ACTIVE,
  354. ServiceStatus,
  355. sizeof(ServiceStatus),
  356. &cbBytesNeeded,
  357. &cbServicesReturned,
  358. &ResumeHandle) ||
  359. (GetLastError() == ERROR_MORE_DATA)) {
  360. for (i=0; i<cbServicesReturned; i++) {
  361. printf("\n\n***********************************************************\n");
  362. printf("%ws\n", ServiceStatus[i].lpServiceName);
  363. RestartDevicesUsingService(ServiceStatus[i].lpServiceName);
  364. printf("***********************************************************\n");
  365. }
  366. }
  367. CloseServiceHandle(hServiceManager);
  368. }
  369. }