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
442 lines
10 KiB
/*++
|
|
|
|
Copyright (c) 1997 Microsoft Corporation
|
|
|
|
Module Name:
|
|
|
|
bootstat.c
|
|
|
|
Abstract:
|
|
|
|
Manipulates the boot status data file.
|
|
|
|
Author:
|
|
|
|
Peter Wieland (peterwie) 01-18-01
|
|
|
|
Revision History:
|
|
|
|
--*/
|
|
|
|
#include "bldr.h"
|
|
#include "bootstatus.h"
|
|
|
|
#include <stdio.h>
|
|
|
|
#define FIELD_SIZE(type, field) sizeof(((type *)0)->field)
|
|
#define FIELD_OFFSET_AND_SIZE(n) {FIELD_OFFSET(BSD_BOOT_STATUS_DATA, n), FIELD_SIZE(BSD_BOOT_STATUS_DATA, n)}
|
|
|
|
VOID
|
|
BlAutoAdvancedBoot(
|
|
IN OUT PCHAR *LoadOptions,
|
|
IN BSD_LAST_BOOT_STATUS LastBootStatus,
|
|
IN ULONG AdvancedBootMode
|
|
)
|
|
{
|
|
CHAR bootStatusString[32];
|
|
PCHAR advancedBootString = NULL;
|
|
|
|
ULONG newLoadOptionsLength;
|
|
PCHAR newLoadOptions;
|
|
|
|
//
|
|
// Write the last boot status into a string.
|
|
//
|
|
|
|
sprintf(bootStatusString, "LastBootStatus=%d", LastBootStatus);
|
|
|
|
//
|
|
// Based on the advanced boot mode indicated by the caller, adjust the
|
|
// boot options.
|
|
//
|
|
|
|
if (AdvancedBootMode != -1) {
|
|
advancedBootString = BlGetAdvancedBootLoadOptions(AdvancedBootMode);
|
|
}
|
|
|
|
//
|
|
// Determine the length of the new load options string.
|
|
//
|
|
|
|
newLoadOptionsLength = (ULONG)strlen(bootStatusString) + 1;
|
|
|
|
if(*LoadOptions != NULL) {
|
|
newLoadOptionsLength += (ULONG)strlen(*LoadOptions) + 1;
|
|
}
|
|
|
|
if(advancedBootString) {
|
|
newLoadOptionsLength += (ULONG)strlen(advancedBootString) + 1;
|
|
}
|
|
|
|
newLoadOptions = BlAllocateHeap(newLoadOptionsLength * sizeof(UCHAR));
|
|
|
|
if(newLoadOptions == NULL) {
|
|
return;
|
|
}
|
|
|
|
//
|
|
// Concatenate all the strings together.
|
|
//
|
|
|
|
sprintf(newLoadOptions, "%s %s %s",
|
|
((*LoadOptions != NULL) ? *LoadOptions : ""),
|
|
((advancedBootString != NULL) ? advancedBootString : ""),
|
|
bootStatusString);
|
|
|
|
if(AdvancedBootMode != -1) {
|
|
BlDoAdvancedBootLoadProcessing(AdvancedBootMode);
|
|
}
|
|
|
|
*LoadOptions = newLoadOptions;
|
|
|
|
return;
|
|
}
|
|
|
|
ARC_STATUS
|
|
BlGetSetBootStatusData(
|
|
IN PVOID DataHandle,
|
|
IN BOOLEAN Get,
|
|
IN RTL_BSD_ITEM_TYPE DataItem,
|
|
IN PVOID DataBuffer,
|
|
IN ULONG DataBufferLength,
|
|
OUT PULONG BytesReturned OPTIONAL
|
|
)
|
|
{
|
|
ULONG fileId = (ULONG) ((ULONG_PTR) DataHandle);
|
|
|
|
struct {
|
|
ULONG FieldOffset;
|
|
ULONG FieldLength;
|
|
} bootStatusFields[] = {
|
|
FIELD_OFFSET_AND_SIZE(Version),
|
|
FIELD_OFFSET_AND_SIZE(ProductType),
|
|
FIELD_OFFSET_AND_SIZE(AutoAdvancedBoot),
|
|
FIELD_OFFSET_AND_SIZE(AdvancedBootMenuTimeout),
|
|
FIELD_OFFSET_AND_SIZE(LastBootSucceeded),
|
|
FIELD_OFFSET_AND_SIZE(LastBootShutdown)
|
|
};
|
|
|
|
ULONG dataFileVersion;
|
|
|
|
LARGE_INTEGER fileOffset;
|
|
ULONG itemLength;
|
|
|
|
ULONG bytesRead;
|
|
|
|
ARC_STATUS status;
|
|
|
|
ASSERT(RtlBsdItemMax == (sizeof(bootStatusFields) / sizeof(bootStatusFields[0])));
|
|
|
|
//
|
|
// Read the version number out of the data file.
|
|
//
|
|
|
|
fileOffset.QuadPart = 0;
|
|
|
|
status = BlSeek(fileId, &fileOffset, SeekAbsolute);
|
|
|
|
if(status != ESUCCESS) {
|
|
return status;
|
|
}
|
|
|
|
status = BlRead(fileId,
|
|
&dataFileVersion,
|
|
sizeof(ULONG),
|
|
&bytesRead);
|
|
|
|
if(status != ESUCCESS) {
|
|
return status;
|
|
}
|
|
|
|
//
|
|
// If the data item requsted isn't one we have code to handle then
|
|
// return invalid parameter.
|
|
//
|
|
|
|
if(DataItem >= (sizeof(bootStatusFields) / sizeof(bootStatusFields[0]))) {
|
|
return EINVAL;
|
|
}
|
|
|
|
fileOffset.QuadPart = bootStatusFields[DataItem].FieldOffset;
|
|
itemLength = bootStatusFields[DataItem].FieldLength;
|
|
|
|
//
|
|
// If the data item offset is beyond the end of the file then return a
|
|
// versioning error.
|
|
//
|
|
|
|
if((fileOffset.QuadPart + itemLength) > dataFileVersion) {
|
|
return EINVAL;
|
|
}
|
|
|
|
if(DataBufferLength < itemLength) {
|
|
DataBufferLength = itemLength;
|
|
return EINVAL;
|
|
}
|
|
|
|
status = BlSeek(fileId, &fileOffset, SeekAbsolute);
|
|
|
|
if(status != ESUCCESS) {
|
|
return status;
|
|
}
|
|
|
|
if(Get) {
|
|
status = BlRead(fileId,
|
|
DataBuffer,
|
|
itemLength,
|
|
&bytesRead);
|
|
|
|
} else {
|
|
status = BlWrite(fileId,
|
|
DataBuffer,
|
|
itemLength,
|
|
&bytesRead);
|
|
}
|
|
|
|
if((status == ESUCCESS) && ARGUMENT_PRESENT(BytesReturned)) {
|
|
*BytesReturned = bytesRead;
|
|
}
|
|
|
|
return status;
|
|
}
|
|
|
|
ARC_STATUS
|
|
BlLockBootStatusData(
|
|
IN ULONG SystemPartitionId,
|
|
IN PCHAR SystemPartition,
|
|
IN PCHAR SystemDirectory,
|
|
OUT PVOID *DataHandle
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine opens the boot status data file.
|
|
|
|
Arguments:
|
|
|
|
SystemPartitionId - if non-zero this is the arc file id of the system
|
|
partition. This will be used to locate the system
|
|
directory instead of the system partition name (below).
|
|
|
|
SystemPartition - the arc name of the system partition. Ignored if
|
|
SystemPartitionId is non-zero.
|
|
|
|
SystemDirectory - the name of the system directory.
|
|
|
|
DataHandle - returns a handle to the boot status data.
|
|
|
|
Return Value:
|
|
|
|
ESUCCESS if the status data could be locked, or error indicating why not.
|
|
|
|
--*/
|
|
{
|
|
ULONG driveId;
|
|
|
|
CHAR filePath[100];
|
|
ULONG fileId;
|
|
|
|
ARC_STATUS status;
|
|
|
|
if(SystemPartitionId == 0) {
|
|
|
|
//
|
|
// Attempt to open the system partition
|
|
//
|
|
|
|
status = ArcOpen(SystemPartition, ArcOpenReadWrite, &driveId);
|
|
|
|
if(status != ESUCCESS) {
|
|
return status;
|
|
}
|
|
} else {
|
|
driveId = SystemPartitionId;
|
|
}
|
|
|
|
//
|
|
// Now attempt to open the file <SystemDirectory>\bootstat.dat
|
|
//
|
|
if (sizeof(filePath) < strlen(SystemDirectory) + strlen(BSD_FILE_NAME) + 1) {
|
|
return ENOMEM;
|
|
}
|
|
strcpy(filePath, SystemDirectory);
|
|
strcat(filePath, BSD_FILE_NAME);
|
|
|
|
status = BlOpen(driveId, filePath, ArcOpenReadWrite, &fileId);
|
|
|
|
if(SystemPartitionId == 0) {
|
|
//
|
|
// Close the drive.
|
|
//
|
|
|
|
ArcClose(driveId);
|
|
}
|
|
|
|
//
|
|
// The file doesn't exist so we don't know the state of the last boot.
|
|
//
|
|
|
|
if(status != ESUCCESS) {
|
|
return status;
|
|
}
|
|
|
|
*DataHandle = (PVOID) ((ULONG_PTR) fileId);
|
|
|
|
return ESUCCESS;
|
|
}
|
|
|
|
|
|
VOID
|
|
BlUnlockBootStatusData(
|
|
IN PVOID DataHandle
|
|
)
|
|
{
|
|
ULONG fileId = (ULONG) ((ULONG_PTR) DataHandle);
|
|
|
|
BlClose(fileId);
|
|
return;
|
|
}
|
|
|
|
ULONG
|
|
BlGetLastBootStatus(
|
|
IN PVOID DataHandle,
|
|
OUT BSD_LAST_BOOT_STATUS *LastBootStatus
|
|
)
|
|
{
|
|
UCHAR lastBootGood;
|
|
UCHAR lastShutdownGood;
|
|
UCHAR aabEnabled;
|
|
|
|
ULONG advancedBootMode = (ULONG)-1;
|
|
|
|
ARC_STATUS status;
|
|
|
|
*LastBootStatus = BsdLastBootGood;
|
|
|
|
//
|
|
// The file contains a simple data structure so i can avoid parsing an
|
|
// INI file. If this proves to be insufficient for policy management then
|
|
// we'll change it into an ini file.
|
|
//
|
|
|
|
//
|
|
// Read the last boot status.
|
|
//
|
|
|
|
status = BlGetSetBootStatusData(DataHandle,
|
|
TRUE,
|
|
RtlBsdItemBootGood,
|
|
&lastBootGood,
|
|
sizeof(UCHAR),
|
|
NULL);
|
|
|
|
if(status != ESUCCESS) {
|
|
*LastBootStatus = BsdLastBootUnknown;
|
|
return advancedBootMode;
|
|
}
|
|
|
|
status = BlGetSetBootStatusData(DataHandle,
|
|
TRUE,
|
|
RtlBsdItemBootShutdown,
|
|
&lastShutdownGood,
|
|
sizeof(UCHAR),
|
|
NULL);
|
|
|
|
if(status != ESUCCESS) {
|
|
*LastBootStatus = BsdLastBootUnknown;
|
|
return advancedBootMode;
|
|
}
|
|
|
|
status = BlGetSetBootStatusData(DataHandle,
|
|
TRUE,
|
|
RtlBsdItemAabEnabled,
|
|
&aabEnabled,
|
|
sizeof(UCHAR),
|
|
NULL);
|
|
|
|
if(status != ESUCCESS) {
|
|
*LastBootStatus = BsdLastBootUnknown;
|
|
return advancedBootMode;
|
|
}
|
|
|
|
//
|
|
// If the system was shutdown cleanly then don't bother to check if the
|
|
// boot was good.
|
|
//
|
|
|
|
if(lastShutdownGood) {
|
|
return advancedBootMode;
|
|
}
|
|
|
|
//
|
|
// Determine the last boot status & what action to take.
|
|
//
|
|
|
|
if(lastBootGood == FALSE) {
|
|
|
|
//
|
|
// Enable last known good.
|
|
//
|
|
|
|
advancedBootMode = 6;
|
|
*LastBootStatus = BsdLastBootFailed;
|
|
} else if(lastShutdownGood == FALSE) {
|
|
|
|
//
|
|
// Enable safe mode without networking.
|
|
//
|
|
|
|
advancedBootMode = 0;
|
|
*LastBootStatus = BsdLastBootNotShutdown;
|
|
}
|
|
|
|
//
|
|
// Now disable auto safemode actions if requested.
|
|
//
|
|
|
|
if(aabEnabled == FALSE) {
|
|
advancedBootMode = (ULONG)-1;
|
|
}
|
|
|
|
return advancedBootMode;
|
|
}
|
|
|
|
VOID
|
|
BlWriteBootStatusFlags(
|
|
IN ULONG SystemPartitionId,
|
|
IN PUCHAR SystemDirectory,
|
|
IN BOOLEAN LastBootSucceeded,
|
|
IN BOOLEAN LastBootShutdown
|
|
)
|
|
{
|
|
PVOID dataHandle;
|
|
|
|
ARC_STATUS status;
|
|
|
|
status = BlLockBootStatusData(SystemPartitionId,
|
|
NULL,
|
|
(PCHAR)SystemDirectory,
|
|
&dataHandle);
|
|
|
|
if(status == ESUCCESS) {
|
|
|
|
BlGetSetBootStatusData(dataHandle,
|
|
FALSE,
|
|
RtlBsdItemBootGood,
|
|
&LastBootSucceeded,
|
|
sizeof(UCHAR),
|
|
NULL);
|
|
|
|
BlGetSetBootStatusData(dataHandle,
|
|
FALSE,
|
|
RtlBsdItemBootShutdown,
|
|
&LastBootShutdown,
|
|
sizeof(UCHAR),
|
|
NULL);
|
|
|
|
BlUnlockBootStatusData(dataHandle);
|
|
}
|
|
|
|
return;
|
|
}
|