|
|
/*++
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; }
|