windows-nt/Source/XPSP1/NT/sdktools/nvram/nvram.c
2020-09-26 16:20:57 +08:00

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