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.

414 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. CM_REMOVE_NO_RESTART
  225. );
  226. if (cr == CR_REMOVE_VETOED) {
  227. //
  228. // Someone vetoed the removal of this device!
  229. //
  230. // This is here for logging purposes only. If no logging is
  231. // required then there is no need for this check.
  232. //
  233. printf("\tVetoed 0x%X %ws\n", VetoType, VetoName);
  234. }
  235. if (cr != CR_SUCCESS) {
  236. //
  237. // If we couldn't stop one of the devices then we might as well
  238. // stop since we are going to need a reboot.
  239. //
  240. printf("\tFailed with 0x%X!\n", cr);
  241. b = FALSE;
  242. break;
  243. }
  244. } else {
  245. //
  246. // If we couldn't locate one of the devices then there is no need to
  247. // continue through the list since a reboot will be needed.
  248. //
  249. printf("\tCouldn't locate the devnode, error 0x%X!\n", cr);
  250. b = FALSE;
  251. break;
  252. }
  253. }
  254. printf("\n");
  255. if (b) {
  256. bIsDriverLoaded = IsDriverLoaded(ServiceName);
  257. printf("%ws %ws loaded\n\n",
  258. ServiceName,
  259. bIsDriverLoaded
  260. ? TEXT("is")
  261. : TEXT("is NOT")
  262. );
  263. //
  264. // If the driver did not unload, even after we stopped all the
  265. // devices using it, the we need to reboot!
  266. //
  267. if (bIsDriverLoaded) {
  268. b = FALSE;
  269. }
  270. }
  271. //
  272. // At this point we need to enumerate through all the devices once again
  273. // and restart them all. It doesn't matter whether we succeeded or not in
  274. // stopping them all, we still need to restart them.
  275. //
  276. for (p=Buffer, i=0; *p; p+=(lstrlen(p) + 1), i++) {
  277. printf("Starting device %ws\n", p);
  278. if ((cr = CM_Locate_DevNode(&DevNode, p, 0)) == CR_SUCCESS) {
  279. //
  280. // NOTE: For Whistler we will call CM_Setup_DevNode with the
  281. // CM_SETUP_DEVNODE_RESET flag which will clear the
  282. // CM_REMOVE_NO_RESTART flag we set earlier. These two flags
  283. // ensure that the devnode will not get restarted by some other
  284. // program or driver until we want them to.
  285. //
  286. if ((cr = CM_Setup_DevNode(DevNode, CM_SETUP_DEVNODE_READY)) == CR_SUCCESS) {
  287. //
  288. // We successfully restarted the device, lets make sure that it
  289. // started and doesn't have any problems. We will only make
  290. // this check if the device was started before.
  291. //
  292. if (DeviceInfo[i].DevNodeStarted == TRUE) {
  293. if ((CM_Get_DevNode_Status(&Status, &Problem, DevNode, 0) != CR_SUCCESS) ||
  294. !(Status & DN_STARTED)) {
  295. //
  296. // We couldn't get the status of this device, or it did not
  297. // restart properly, so we will need to reboot.
  298. //
  299. printf("\tDevice could not be restarted!\n");
  300. b = FALSE;
  301. }
  302. }
  303. } else {
  304. //
  305. // We couldn't restart this device, so we will need to reboot.
  306. //
  307. printf("\tDevice could not be restarted, error 0x%X!\n", cr);
  308. b = FALSE;
  309. }
  310. } else {
  311. //
  312. // We couldn't locate the devnode to restart it.
  313. //
  314. printf("\tCouldn't locate the devnode, error 0x%X!\n", cr);
  315. b = FALSE;
  316. }
  317. }
  318. printf("%ws %ws loaded\n",
  319. ServiceName,
  320. IsDriverLoaded(ServiceName)
  321. ? TEXT("is")
  322. : TEXT("is NOT")
  323. );
  324. } except(EXCEPTION_EXECUTE_HANDLER) {
  325. Buffer = Buffer;
  326. DeviceInfo = DeviceInfo;
  327. b = FALSE;
  328. }
  329. clean0:
  330. if (Buffer) {
  331. LocalFree(Buffer);
  332. }
  333. if (DeviceInfo) {
  334. LocalFree(DeviceInfo);
  335. }
  336. return b;
  337. }
  338. int
  339. __cdecl
  340. wmain(
  341. IN int argc,
  342. IN char *argv[]
  343. )
  344. {
  345. BOOL bDriverUnloaded;
  346. if (argc != 2) {
  347. printf("Usage: StopDevs X\n");
  348. printf("\twhere X is the name of the service.\n");
  349. return 0;
  350. }
  351. bDriverUnloaded = RestartDevicesUsingService((LPTSTR)argv[1]);
  352. if (bDriverUnloaded) {
  353. printf("\n\nThe driver unloaded, no need to reboot!\n\n");
  354. return 1;
  355. } else {
  356. printf("\n\nThe driver did NOT unload, a reboot is required!\n\n");
  357. return 0;
  358. }
  359. }