631 lines
15 KiB
C
631 lines
15 KiB
C
/*++
|
|
|
|
Copyright (c) 1993-1996 Microsoft Corporation
|
|
|
|
Module Name:
|
|
|
|
nvram.c
|
|
|
|
Abstract:
|
|
|
|
ARC/NV-RAM manipulation routines for 32-bit winnt setup.
|
|
Also works on boot.ini on i386 machines.
|
|
|
|
Author:
|
|
|
|
Ted Miller (tedm) 19-December-1993
|
|
|
|
Revision History:
|
|
|
|
--*/
|
|
|
|
|
|
#include "nvram.h"
|
|
|
|
typedef enum {
|
|
BootVarSystemPartition,
|
|
BootVarOsLoader,
|
|
BootVarOsLoadPartition,
|
|
BootVarOsLoadFilename,
|
|
BootVarLoadIdentifier,
|
|
BootVarOsLoadOptions,
|
|
BootVarCountdown,
|
|
BootVarMax
|
|
} BOOT_VARS;
|
|
|
|
PWSTR BootVarNames[BootVarMax] = { L"SYSTEMPARTITION",
|
|
L"OSLOADER",
|
|
L"OSLOADPARTITION",
|
|
L"OSLOADFILENAME",
|
|
L"LOADIDENTIFIER",
|
|
L"OSLOADOPTIONS",
|
|
L"COUNTDOWN"
|
|
};
|
|
|
|
PWSTR PaddedBootVarNames[BootVarMax] = { L"SYSTEMPARTITION",
|
|
L" OSLOADER",
|
|
L"OSLOADPARTITION",
|
|
L" OSLOADFILENAME",
|
|
L" LOADIDENTIFIER",
|
|
L" OSLOADOPTIONS",
|
|
L" COUNTDOWN"
|
|
};
|
|
|
|
#ifndef i386
|
|
|
|
//
|
|
// Helper macro to make object attribute initialization a little cleaner.
|
|
//
|
|
#define INIT_OBJA(Obja,UnicodeString,UnicodeText) \
|
|
\
|
|
RtlInitUnicodeString((UnicodeString),(UnicodeText)); \
|
|
\
|
|
InitializeObjectAttributes( \
|
|
(Obja), \
|
|
(UnicodeString), \
|
|
OBJ_CASE_INSENSITIVE, \
|
|
NULL, \
|
|
NULL \
|
|
)
|
|
|
|
|
|
|
|
BOOL
|
|
DoSetNvRamVar(
|
|
IN PWSTR VarName,
|
|
IN PWSTR VarValue
|
|
)
|
|
{
|
|
UNICODE_STRING U1,U2;
|
|
|
|
RtlInitUnicodeString(&U1,VarName);
|
|
RtlInitUnicodeString(&U2,VarValue);
|
|
|
|
return(NT_SUCCESS(NtSetSystemEnvironmentValue(&U1,&U2)));
|
|
}
|
|
|
|
|
|
VOID
|
|
PrintNvRamVariable(
|
|
IN PWSTR VariableName,
|
|
IN PWSTR VariableValue
|
|
)
|
|
{
|
|
PWSTR pEnd;
|
|
WCHAR c;
|
|
BOOL FirstComponent = TRUE;
|
|
|
|
while(*VariableValue) {
|
|
|
|
//
|
|
// Find the termination of the current component,
|
|
// which is either a ; or 0.
|
|
//
|
|
pEnd = wcschr(VariableValue,L';');
|
|
if(!pEnd) {
|
|
pEnd = wcschr(VariableValue,0);
|
|
}
|
|
|
|
c = *pEnd;
|
|
*pEnd = 0;
|
|
|
|
wprintf(
|
|
L"%s%s %s\n",
|
|
FirstComponent ? VariableName : L" ",
|
|
FirstComponent ? L":" : L" ",
|
|
VariableValue
|
|
);
|
|
|
|
*pEnd = c;
|
|
|
|
VariableValue = pEnd + (c ? 1 : 0);
|
|
|
|
FirstComponent = FALSE;
|
|
}
|
|
}
|
|
|
|
VOID
|
|
RotateNvRamVariable(
|
|
IN PWSTR VariableValue
|
|
)
|
|
{
|
|
PWSTR pEnd;
|
|
WCHAR Buffer[32768];
|
|
//
|
|
// Find the termination of the current component,
|
|
// which is either a ; or 0.
|
|
//
|
|
pEnd = wcschr(VariableValue,L';');
|
|
if(!pEnd) {
|
|
pEnd = wcschr(VariableValue,0);
|
|
}
|
|
|
|
//
|
|
// Copy VariableValue into Buffer starting at second entry
|
|
//
|
|
wcscpy(Buffer, pEnd + (*pEnd ? 1 : 0));
|
|
|
|
//
|
|
// Append first entry at the end of Buffer
|
|
//
|
|
if (*pEnd) wcscpy(Buffer + wcslen(Buffer), L";");
|
|
|
|
*pEnd = 0;
|
|
|
|
wcscpy(Buffer + wcslen(Buffer), VariableValue);
|
|
|
|
//
|
|
// Copy whole thing back into VariableValue
|
|
//
|
|
wcscpy(VariableValue, Buffer);
|
|
|
|
}
|
|
|
|
int _cdecl main(
|
|
IN int argc,
|
|
IN char *argv[]
|
|
)
|
|
{
|
|
DWORD var;
|
|
UNICODE_STRING UnicodeString;
|
|
NTSTATUS Status;
|
|
BOOLEAN OldPriv;
|
|
WCHAR Buffer[32768];
|
|
WCHAR Buffer1[32768];
|
|
WCHAR Buffer2[32768];
|
|
|
|
Status = RtlAdjustPrivilege(
|
|
SE_SYSTEM_ENVIRONMENT_PRIVILEGE,
|
|
TRUE,
|
|
FALSE,
|
|
&OldPriv
|
|
);
|
|
|
|
if(!NT_SUCCESS(Status)) {
|
|
wprintf(L"Insufficient privilege.\n");
|
|
return(0);
|
|
}
|
|
|
|
if(argc == 1) {
|
|
|
|
for(var=0; var<BootVarMax; var++) {
|
|
|
|
RtlInitUnicodeString(&UnicodeString,BootVarNames[var]);
|
|
|
|
Status = NtQuerySystemEnvironmentValue(
|
|
&UnicodeString,
|
|
Buffer,
|
|
SIZECHARS(Buffer),
|
|
NULL
|
|
);
|
|
|
|
if(NT_SUCCESS(Status)) {
|
|
PrintNvRamVariable(PaddedBootVarNames[var],Buffer);
|
|
} else {
|
|
wprintf(L"%s: <empty>\n",PaddedBootVarNames[var]);
|
|
}
|
|
|
|
wprintf(L"\n");
|
|
}
|
|
}
|
|
|
|
if((argc == 2) && !lstrcmpiA(argv[1],"rotate")){
|
|
|
|
for(var=0; var<BootVarMax; var++) {
|
|
|
|
RtlInitUnicodeString(&UnicodeString,BootVarNames[var]);
|
|
|
|
Status = NtQuerySystemEnvironmentValue(
|
|
&UnicodeString,
|
|
Buffer,
|
|
SIZECHARS(Buffer),
|
|
NULL
|
|
);
|
|
|
|
if(NT_SUCCESS(Status)) {
|
|
RotateNvRamVariable(Buffer);
|
|
printf(
|
|
"Setting variable %ws to %ws [%s]\n",
|
|
UnicodeString.Buffer,
|
|
Buffer,
|
|
DoSetNvRamVar(UnicodeString.Buffer,Buffer) ? "OK" : "Error"
|
|
);
|
|
} else {
|
|
wprintf(L"%s: <empty>\n",PaddedBootVarNames[var]);
|
|
}
|
|
|
|
wprintf(L"\n");
|
|
}
|
|
}
|
|
|
|
if((argc == 5) && !lstrcmpiA(argv[1]+1,"set") && !lstrcmpA(argv[3],"=")) {
|
|
|
|
MultiByteToWideChar(
|
|
CP_OEMCP,
|
|
MB_PRECOMPOSED,
|
|
argv[2],
|
|
-1,
|
|
Buffer1,
|
|
SIZECHARS(Buffer1)
|
|
);
|
|
|
|
MultiByteToWideChar(
|
|
CP_OEMCP,
|
|
MB_PRECOMPOSED,
|
|
argv[4],
|
|
-1,
|
|
Buffer2,
|
|
SIZECHARS(Buffer2)
|
|
);
|
|
|
|
printf(
|
|
"Setting variable %ws to %ws [%s]\n",
|
|
Buffer1,
|
|
Buffer2,
|
|
DoSetNvRamVar(Buffer1,Buffer2) ? "OK" : "Error"
|
|
);
|
|
}
|
|
|
|
return(0);
|
|
}
|
|
|
|
#else
|
|
|
|
TCHAR LoadID[500]; // load identifier (no quotes)
|
|
TCHAR CountDown[100]; // countdown timer
|
|
TCHAR OsLoadOptions[500]; // load options
|
|
TCHAR OsName[500]; // name of default os
|
|
|
|
TCHAR OsLine[500]; // complete line of os description and options
|
|
|
|
#define STR_BOOTINI TEXT("c:\\boot.ini")
|
|
#define STR_BOOTLDR TEXT("boot loader")
|
|
#define STR_TIMEOUT TEXT("timeout")
|
|
#define STR_DEFAULT TEXT("default")
|
|
#define STR_OPERATINGSYS TEXT("operating systems")
|
|
#define STR_NULL TEXT("")
|
|
|
|
//
|
|
// HandleOption - add option to OsLoadOptions
|
|
//
|
|
|
|
VOID HandleOption( TCHAR* Option )
|
|
{
|
|
TCHAR SlashOption[200];
|
|
TCHAR SlashOptionSlash[200];
|
|
//
|
|
// find out if option already exists
|
|
// add blank to end to prevent debug from matching debugport
|
|
//
|
|
|
|
wsprintf( SlashOption, TEXT("/%s "), Option );
|
|
wsprintf( SlashOptionSlash, TEXT("/%s/"), Option );
|
|
|
|
if( wcsstr( OsLoadOptions, SlashOption ) ||
|
|
wcsstr( OsLoadOptions, SlashOptionSlash ) )
|
|
{
|
|
printf("option already exists: %ws\n",Option);
|
|
}
|
|
else
|
|
{
|
|
//
|
|
// append option without the trailing blank
|
|
//
|
|
|
|
printf("added option %ws\n",Option);
|
|
lstrcat( OsLoadOptions, TEXT("/") );
|
|
lstrcat( OsLoadOptions, Option );
|
|
}
|
|
}
|
|
|
|
//
|
|
// WriteBootIni - update the boot.ini file with our changes
|
|
//
|
|
|
|
VOID WriteBootIni()
|
|
{
|
|
DWORD FileAttr;
|
|
|
|
//
|
|
// Get file attributes of boot.ini for later restoration
|
|
//
|
|
|
|
FileAttr= GetFileAttributes( STR_BOOTINI );
|
|
|
|
//
|
|
// Change file attributes on boot.ini so we can write to it.
|
|
//
|
|
|
|
if( !SetFileAttributes( STR_BOOTINI, FILE_ATTRIBUTE_NORMAL ) )
|
|
{
|
|
printf("Failed to turn off read-only on boot.ini (lasterr= %d)\n",
|
|
GetLastError() );
|
|
}
|
|
|
|
//
|
|
// Update boot.ini strings
|
|
//
|
|
|
|
if( !WritePrivateProfileString( STR_BOOTLDR, STR_TIMEOUT,
|
|
CountDown, STR_BOOTINI ) )
|
|
{
|
|
printf("failed to write timeout (lasterr= %d)\n",GetLastError());
|
|
}
|
|
|
|
//
|
|
// create the osline from its parts
|
|
//
|
|
|
|
wsprintf(OsLine, TEXT("\"%s\"%s"), LoadID, OsLoadOptions );
|
|
|
|
if( !WritePrivateProfileString( STR_OPERATINGSYS, OsName,
|
|
OsLine, STR_BOOTINI ) )
|
|
{
|
|
printf("failed to write OS line (lasterr= %d)\n",GetLastError());
|
|
}
|
|
|
|
//
|
|
// Restore boot.ini file attributes
|
|
//
|
|
|
|
if( FileAttr != 0xFFFFFFFF )
|
|
{
|
|
SetFileAttributes( STR_BOOTINI, FileAttr );
|
|
}
|
|
|
|
}
|
|
|
|
//
|
|
// Usage - print out usage information
|
|
//
|
|
|
|
VOID Usage()
|
|
{
|
|
printf("\nUsage:\n");
|
|
printf(" no parameters: prints current settings.\n");
|
|
printf(" /set parameter = value : sets value in boot.ini\n");
|
|
printf(" rotate : rotates default build through boot options\n");
|
|
printf("\n");
|
|
printf("Example: nvram /set osloadoptions = debug\n");
|
|
printf(" This will set the debug option on\n\n");
|
|
printf("Available options:\n");
|
|
printf(" loadidentifier, osloadoptions, countdown\n");
|
|
}
|
|
|
|
|
|
int _cdecl main(
|
|
IN int argc,
|
|
IN char *argv[]
|
|
)
|
|
{
|
|
DWORD dwStatus;
|
|
LPWSTR* pArgs;
|
|
|
|
// parse command line in unicode
|
|
|
|
pArgs= CommandLineToArgvW( GetCommandLine(), &argc );
|
|
|
|
//
|
|
// Get the boot information from boot.ini
|
|
//
|
|
|
|
// timeout
|
|
|
|
dwStatus= GetPrivateProfileString(
|
|
STR_BOOTLDR,
|
|
STR_TIMEOUT,
|
|
STR_NULL,
|
|
CountDown,
|
|
SIZECHARS(CountDown),
|
|
STR_BOOTINI );
|
|
if( !dwStatus )
|
|
{
|
|
printf("Failed to get timeout value\n");
|
|
return(-1);
|
|
}
|
|
|
|
// default os description and options
|
|
|
|
dwStatus= GetPrivateProfileString(
|
|
STR_BOOTLDR,
|
|
STR_DEFAULT,
|
|
STR_NULL,
|
|
OsName,
|
|
SIZECHARS(OsName),
|
|
STR_BOOTINI );
|
|
if( !dwStatus )
|
|
{
|
|
printf("Failed to get default OS name\n");
|
|
return(-1);
|
|
}
|
|
|
|
dwStatus= GetPrivateProfileString(
|
|
STR_OPERATINGSYS,
|
|
OsName,
|
|
STR_NULL,
|
|
OsLine,
|
|
SIZECHARS(OsLine),
|
|
STR_BOOTINI );
|
|
if( !dwStatus )
|
|
{
|
|
printf("Failed to get default os description\n");
|
|
return(-1);
|
|
}
|
|
|
|
//
|
|
// Now parse the line into description and options.
|
|
// If it starts with a quote, it may have options.
|
|
// If it doesn't start with a quote, it won't.
|
|
//
|
|
|
|
*LoadID= *OsLoadOptions= TEXT('\0');
|
|
|
|
if( *OsLine == TEXT('"') )
|
|
{
|
|
INT i;
|
|
|
|
for( i=1; OsLine[i]; i++ )
|
|
{
|
|
LoadID[i-1]= OsLine[i];
|
|
if( OsLine[i] == TEXT('"') )
|
|
break;
|
|
}
|
|
|
|
if( OsLine[i] )
|
|
{
|
|
LoadID[i-1]= TEXT('\0'); // don't copy final quote
|
|
lstrcpy( OsLoadOptions, &OsLine[i+1] );
|
|
lstrcat( OsLoadOptions, TEXT(" ") ); // all options end with blank
|
|
}
|
|
}
|
|
else
|
|
{
|
|
lstrcpy( LoadID, OsLine );
|
|
lstrcpy( OsLoadOptions, TEXT("") );
|
|
}
|
|
|
|
// no parameters prints out values
|
|
|
|
if( argc == 1 )
|
|
{
|
|
printf("%ws: %ws\n",PaddedBootVarNames[BootVarLoadIdentifier], LoadID);
|
|
printf("%ws: %ws\n",PaddedBootVarNames[BootVarOsLoadOptions], OsLoadOptions);
|
|
printf("%ws: %ws\n",PaddedBootVarNames[BootVarCountdown], CountDown);
|
|
}
|
|
|
|
// -set parameter = value
|
|
// sets parameter to some value
|
|
|
|
if( (argc == 2) &&
|
|
!lstrcmpiW(pArgs[1],L"rotate") )
|
|
{
|
|
INT i;
|
|
DWORD FileAttr;
|
|
|
|
//
|
|
// Read in all boot options
|
|
//
|
|
|
|
dwStatus= GetPrivateProfileString(
|
|
STR_OPERATINGSYS,
|
|
NULL,
|
|
STR_NULL,
|
|
OsLine,
|
|
SIZECHARS(OsLine),
|
|
STR_BOOTINI );
|
|
if( !dwStatus )
|
|
{
|
|
printf("Failed to get os section\n");
|
|
return(-1);
|
|
}
|
|
|
|
//
|
|
// read through boot options until we find default entry
|
|
//
|
|
|
|
i = 0;
|
|
|
|
while( lstrcmpiW( OsName, &(OsLine[i]) ) ){
|
|
|
|
i = i + wcslen(&OsLine[i]) + 1;
|
|
}
|
|
|
|
//
|
|
// increment one more entry
|
|
//
|
|
|
|
i = i + wcslen(&OsLine[i]) + 1;
|
|
|
|
//
|
|
// if we've gone off the end then start over
|
|
//
|
|
|
|
if (!lstrcmpiW( &(OsLine[i]), L"\0\0" ) ){
|
|
i = 0;
|
|
}
|
|
|
|
//
|
|
// Get file attributes of boot.ini for later restoration
|
|
//
|
|
|
|
FileAttr= GetFileAttributes( STR_BOOTINI );
|
|
|
|
//
|
|
// Change file attributes on boot.ini so we can write to it.
|
|
//
|
|
|
|
if( !SetFileAttributes( STR_BOOTINI, FILE_ATTRIBUTE_NORMAL ) )
|
|
{
|
|
printf("Failed to turn off read-only on boot.ini (lasterr= %d)\n",
|
|
GetLastError() );
|
|
}
|
|
|
|
if( !WritePrivateProfileString( STR_BOOTLDR, STR_DEFAULT,
|
|
&(OsLine[i]), STR_BOOTINI ) )
|
|
{
|
|
printf("failed to write default (lasterr= %d)\n",GetLastError());
|
|
}
|
|
|
|
//
|
|
// Restore boot.ini file attributes
|
|
//
|
|
|
|
if( FileAttr != 0xFFFFFFFF )
|
|
{
|
|
SetFileAttributes( STR_BOOTINI, FileAttr );
|
|
}
|
|
|
|
}
|
|
if( (argc == 5) &&
|
|
!lstrcmpiW(pArgs[1]+1,L"set") &&
|
|
!lstrcmpW(pArgs[3],L"=") )
|
|
{
|
|
INT i;
|
|
|
|
// see if we understand parameter
|
|
|
|
for( i=0; i<BootVarMax; i++ )
|
|
{
|
|
if( lstrcmpiW( pArgs[2], BootVarNames[i] ) == 0 )
|
|
break;
|
|
}
|
|
|
|
// handle the ones we can
|
|
|
|
switch( i )
|
|
{
|
|
default:
|
|
printf("Not valid parameter name to set: %ws\n",pArgs[2]);
|
|
Usage();
|
|
return(-1);
|
|
break;
|
|
|
|
case BootVarLoadIdentifier:
|
|
lstrcpyW( LoadID, pArgs[4] );
|
|
break;
|
|
|
|
case BootVarOsLoadOptions:
|
|
HandleOption( pArgs[4] );
|
|
break;
|
|
|
|
case BootVarCountdown:
|
|
lstrcpyW( CountDown, pArgs[4] );
|
|
break;
|
|
}
|
|
|
|
WriteBootIni();
|
|
}
|
|
|
|
// -?
|
|
// usage message
|
|
|
|
if( argc == 2 && !lstrcmpW(pArgs[1]+1, L"?") )
|
|
{
|
|
Usage();
|
|
}
|
|
|
|
return(0);
|
|
}
|
|
|
|
#endif
|