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.

442 lines
10 KiB

  1. /*++
  2. Copyright (c) 1997 Microsoft Corporation
  3. Module Name:
  4. bootstat.c
  5. Abstract:
  6. Manipulates the boot status data file.
  7. Author:
  8. Peter Wieland (peterwie) 01-18-01
  9. Revision History:
  10. --*/
  11. #include "bldr.h"
  12. #include "bootstatus.h"
  13. #include <stdio.h>
  14. #define FIELD_SIZE(type, field) sizeof(((type *)0)->field)
  15. #define FIELD_OFFSET_AND_SIZE(n) {FIELD_OFFSET(BSD_BOOT_STATUS_DATA, n), FIELD_SIZE(BSD_BOOT_STATUS_DATA, n)}
  16. VOID
  17. BlAutoAdvancedBoot(
  18. IN OUT PCHAR *LoadOptions,
  19. IN BSD_LAST_BOOT_STATUS LastBootStatus,
  20. IN ULONG AdvancedBootMode
  21. )
  22. {
  23. CHAR bootStatusString[32];
  24. PCHAR advancedBootString = NULL;
  25. ULONG newLoadOptionsLength;
  26. PCHAR newLoadOptions;
  27. //
  28. // Write the last boot status into a string.
  29. //
  30. sprintf(bootStatusString, "LastBootStatus=%d", LastBootStatus);
  31. //
  32. // Based on the advanced boot mode indicated by the caller, adjust the
  33. // boot options.
  34. //
  35. if (AdvancedBootMode != -1) {
  36. advancedBootString = BlGetAdvancedBootLoadOptions(AdvancedBootMode);
  37. }
  38. //
  39. // Determine the length of the new load options string.
  40. //
  41. newLoadOptionsLength = (ULONG)strlen(bootStatusString) + 1;
  42. if(*LoadOptions != NULL) {
  43. newLoadOptionsLength += (ULONG)strlen(*LoadOptions) + 1;
  44. }
  45. if(advancedBootString) {
  46. newLoadOptionsLength += (ULONG)strlen(advancedBootString) + 1;
  47. }
  48. newLoadOptions = BlAllocateHeap(newLoadOptionsLength * sizeof(UCHAR));
  49. if(newLoadOptions == NULL) {
  50. return;
  51. }
  52. //
  53. // Concatenate all the strings together.
  54. //
  55. sprintf(newLoadOptions, "%s %s %s",
  56. ((*LoadOptions != NULL) ? *LoadOptions : ""),
  57. ((advancedBootString != NULL) ? advancedBootString : ""),
  58. bootStatusString);
  59. if(AdvancedBootMode != -1) {
  60. BlDoAdvancedBootLoadProcessing(AdvancedBootMode);
  61. }
  62. *LoadOptions = newLoadOptions;
  63. return;
  64. }
  65. ARC_STATUS
  66. BlGetSetBootStatusData(
  67. IN PVOID DataHandle,
  68. IN BOOLEAN Get,
  69. IN RTL_BSD_ITEM_TYPE DataItem,
  70. IN PVOID DataBuffer,
  71. IN ULONG DataBufferLength,
  72. OUT PULONG BytesReturned OPTIONAL
  73. )
  74. {
  75. ULONG fileId = (ULONG) ((ULONG_PTR) DataHandle);
  76. struct {
  77. ULONG FieldOffset;
  78. ULONG FieldLength;
  79. } bootStatusFields[] = {
  80. FIELD_OFFSET_AND_SIZE(Version),
  81. FIELD_OFFSET_AND_SIZE(ProductType),
  82. FIELD_OFFSET_AND_SIZE(AutoAdvancedBoot),
  83. FIELD_OFFSET_AND_SIZE(AdvancedBootMenuTimeout),
  84. FIELD_OFFSET_AND_SIZE(LastBootSucceeded),
  85. FIELD_OFFSET_AND_SIZE(LastBootShutdown)
  86. };
  87. ULONG dataFileVersion;
  88. LARGE_INTEGER fileOffset;
  89. ULONG itemLength;
  90. ULONG bytesRead;
  91. ARC_STATUS status;
  92. ASSERT(RtlBsdItemMax == (sizeof(bootStatusFields) / sizeof(bootStatusFields[0])));
  93. //
  94. // Read the version number out of the data file.
  95. //
  96. fileOffset.QuadPart = 0;
  97. status = BlSeek(fileId, &fileOffset, SeekAbsolute);
  98. if(status != ESUCCESS) {
  99. return status;
  100. }
  101. status = BlRead(fileId,
  102. &dataFileVersion,
  103. sizeof(ULONG),
  104. &bytesRead);
  105. if(status != ESUCCESS) {
  106. return status;
  107. }
  108. //
  109. // If the data item requsted isn't one we have code to handle then
  110. // return invalid parameter.
  111. //
  112. if(DataItem >= (sizeof(bootStatusFields) / sizeof(bootStatusFields[0]))) {
  113. return EINVAL;
  114. }
  115. fileOffset.QuadPart = bootStatusFields[DataItem].FieldOffset;
  116. itemLength = bootStatusFields[DataItem].FieldLength;
  117. //
  118. // If the data item offset is beyond the end of the file then return a
  119. // versioning error.
  120. //
  121. if((fileOffset.QuadPart + itemLength) > dataFileVersion) {
  122. return EINVAL;
  123. }
  124. if(DataBufferLength < itemLength) {
  125. DataBufferLength = itemLength;
  126. return EINVAL;
  127. }
  128. status = BlSeek(fileId, &fileOffset, SeekAbsolute);
  129. if(status != ESUCCESS) {
  130. return status;
  131. }
  132. if(Get) {
  133. status = BlRead(fileId,
  134. DataBuffer,
  135. itemLength,
  136. &bytesRead);
  137. } else {
  138. status = BlWrite(fileId,
  139. DataBuffer,
  140. itemLength,
  141. &bytesRead);
  142. }
  143. if((status == ESUCCESS) && ARGUMENT_PRESENT(BytesReturned)) {
  144. *BytesReturned = bytesRead;
  145. }
  146. return status;
  147. }
  148. ARC_STATUS
  149. BlLockBootStatusData(
  150. IN ULONG SystemPartitionId,
  151. IN PCHAR SystemPartition,
  152. IN PCHAR SystemDirectory,
  153. OUT PVOID *DataHandle
  154. )
  155. /*++
  156. Routine Description:
  157. This routine opens the boot status data file.
  158. Arguments:
  159. SystemPartitionId - if non-zero this is the arc file id of the system
  160. partition. This will be used to locate the system
  161. directory instead of the system partition name (below).
  162. SystemPartition - the arc name of the system partition. Ignored if
  163. SystemPartitionId is non-zero.
  164. SystemDirectory - the name of the system directory.
  165. DataHandle - returns a handle to the boot status data.
  166. Return Value:
  167. ESUCCESS if the status data could be locked, or error indicating why not.
  168. --*/
  169. {
  170. ULONG driveId;
  171. CHAR filePath[100];
  172. ULONG fileId;
  173. ARC_STATUS status;
  174. if(SystemPartitionId == 0) {
  175. //
  176. // Attempt to open the system partition
  177. //
  178. status = ArcOpen(SystemPartition, ArcOpenReadWrite, &driveId);
  179. if(status != ESUCCESS) {
  180. return status;
  181. }
  182. } else {
  183. driveId = SystemPartitionId;
  184. }
  185. //
  186. // Now attempt to open the file <SystemDirectory>\bootstat.dat
  187. //
  188. if (sizeof(filePath) < strlen(SystemDirectory) + strlen(BSD_FILE_NAME) + 1) {
  189. return ENOMEM;
  190. }
  191. strcpy(filePath, SystemDirectory);
  192. strcat(filePath, BSD_FILE_NAME);
  193. status = BlOpen(driveId, filePath, ArcOpenReadWrite, &fileId);
  194. if(SystemPartitionId == 0) {
  195. //
  196. // Close the drive.
  197. //
  198. ArcClose(driveId);
  199. }
  200. //
  201. // The file doesn't exist so we don't know the state of the last boot.
  202. //
  203. if(status != ESUCCESS) {
  204. return status;
  205. }
  206. *DataHandle = (PVOID) ((ULONG_PTR) fileId);
  207. return ESUCCESS;
  208. }
  209. VOID
  210. BlUnlockBootStatusData(
  211. IN PVOID DataHandle
  212. )
  213. {
  214. ULONG fileId = (ULONG) ((ULONG_PTR) DataHandle);
  215. BlClose(fileId);
  216. return;
  217. }
  218. ULONG
  219. BlGetLastBootStatus(
  220. IN PVOID DataHandle,
  221. OUT BSD_LAST_BOOT_STATUS *LastBootStatus
  222. )
  223. {
  224. UCHAR lastBootGood;
  225. UCHAR lastShutdownGood;
  226. UCHAR aabEnabled;
  227. ULONG advancedBootMode = (ULONG)-1;
  228. ARC_STATUS status;
  229. *LastBootStatus = BsdLastBootGood;
  230. //
  231. // The file contains a simple data structure so i can avoid parsing an
  232. // INI file. If this proves to be insufficient for policy management then
  233. // we'll change it into an ini file.
  234. //
  235. //
  236. // Read the last boot status.
  237. //
  238. status = BlGetSetBootStatusData(DataHandle,
  239. TRUE,
  240. RtlBsdItemBootGood,
  241. &lastBootGood,
  242. sizeof(UCHAR),
  243. NULL);
  244. if(status != ESUCCESS) {
  245. *LastBootStatus = BsdLastBootUnknown;
  246. return advancedBootMode;
  247. }
  248. status = BlGetSetBootStatusData(DataHandle,
  249. TRUE,
  250. RtlBsdItemBootShutdown,
  251. &lastShutdownGood,
  252. sizeof(UCHAR),
  253. NULL);
  254. if(status != ESUCCESS) {
  255. *LastBootStatus = BsdLastBootUnknown;
  256. return advancedBootMode;
  257. }
  258. status = BlGetSetBootStatusData(DataHandle,
  259. TRUE,
  260. RtlBsdItemAabEnabled,
  261. &aabEnabled,
  262. sizeof(UCHAR),
  263. NULL);
  264. if(status != ESUCCESS) {
  265. *LastBootStatus = BsdLastBootUnknown;
  266. return advancedBootMode;
  267. }
  268. //
  269. // If the system was shutdown cleanly then don't bother to check if the
  270. // boot was good.
  271. //
  272. if(lastShutdownGood) {
  273. return advancedBootMode;
  274. }
  275. //
  276. // Determine the last boot status & what action to take.
  277. //
  278. if(lastBootGood == FALSE) {
  279. //
  280. // Enable last known good.
  281. //
  282. advancedBootMode = 6;
  283. *LastBootStatus = BsdLastBootFailed;
  284. } else if(lastShutdownGood == FALSE) {
  285. //
  286. // Enable safe mode without networking.
  287. //
  288. advancedBootMode = 0;
  289. *LastBootStatus = BsdLastBootNotShutdown;
  290. }
  291. //
  292. // Now disable auto safemode actions if requested.
  293. //
  294. if(aabEnabled == FALSE) {
  295. advancedBootMode = (ULONG)-1;
  296. }
  297. return advancedBootMode;
  298. }
  299. VOID
  300. BlWriteBootStatusFlags(
  301. IN ULONG SystemPartitionId,
  302. IN PUCHAR SystemDirectory,
  303. IN BOOLEAN LastBootSucceeded,
  304. IN BOOLEAN LastBootShutdown
  305. )
  306. {
  307. PVOID dataHandle;
  308. ARC_STATUS status;
  309. status = BlLockBootStatusData(SystemPartitionId,
  310. NULL,
  311. (PCHAR)SystemDirectory,
  312. &dataHandle);
  313. if(status == ESUCCESS) {
  314. BlGetSetBootStatusData(dataHandle,
  315. FALSE,
  316. RtlBsdItemBootGood,
  317. &LastBootSucceeded,
  318. sizeof(UCHAR),
  319. NULL);
  320. BlGetSetBootStatusData(dataHandle,
  321. FALSE,
  322. RtlBsdItemBootShutdown,
  323. &LastBootShutdown,
  324. sizeof(UCHAR),
  325. NULL);
  326. BlUnlockBootStatusData(dataHandle);
  327. }
  328. return;
  329. }