Source code of Windows XP (NT5)
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.

630 lines
15 KiB

  1. /*++
  2. Copyright (c) 1993-1996 Microsoft Corporation
  3. Module Name:
  4. nvram.c
  5. Abstract:
  6. ARC/NV-RAM manipulation routines for 32-bit winnt setup.
  7. Also works on boot.ini on i386 machines.
  8. Author:
  9. Ted Miller (tedm) 19-December-1993
  10. Revision History:
  11. --*/
  12. #include "nvram.h"
  13. typedef enum {
  14. BootVarSystemPartition,
  15. BootVarOsLoader,
  16. BootVarOsLoadPartition,
  17. BootVarOsLoadFilename,
  18. BootVarLoadIdentifier,
  19. BootVarOsLoadOptions,
  20. BootVarCountdown,
  21. BootVarMax
  22. } BOOT_VARS;
  23. PWSTR BootVarNames[BootVarMax] = { L"SYSTEMPARTITION",
  24. L"OSLOADER",
  25. L"OSLOADPARTITION",
  26. L"OSLOADFILENAME",
  27. L"LOADIDENTIFIER",
  28. L"OSLOADOPTIONS",
  29. L"COUNTDOWN"
  30. };
  31. PWSTR PaddedBootVarNames[BootVarMax] = { L"SYSTEMPARTITION",
  32. L" OSLOADER",
  33. L"OSLOADPARTITION",
  34. L" OSLOADFILENAME",
  35. L" LOADIDENTIFIER",
  36. L" OSLOADOPTIONS",
  37. L" COUNTDOWN"
  38. };
  39. #ifndef i386
  40. //
  41. // Helper macro to make object attribute initialization a little cleaner.
  42. //
  43. #define INIT_OBJA(Obja,UnicodeString,UnicodeText) \
  44. \
  45. RtlInitUnicodeString((UnicodeString),(UnicodeText)); \
  46. \
  47. InitializeObjectAttributes( \
  48. (Obja), \
  49. (UnicodeString), \
  50. OBJ_CASE_INSENSITIVE, \
  51. NULL, \
  52. NULL \
  53. )
  54. BOOL
  55. DoSetNvRamVar(
  56. IN PWSTR VarName,
  57. IN PWSTR VarValue
  58. )
  59. {
  60. UNICODE_STRING U1,U2;
  61. RtlInitUnicodeString(&U1,VarName);
  62. RtlInitUnicodeString(&U2,VarValue);
  63. return(NT_SUCCESS(NtSetSystemEnvironmentValue(&U1,&U2)));
  64. }
  65. VOID
  66. PrintNvRamVariable(
  67. IN PWSTR VariableName,
  68. IN PWSTR VariableValue
  69. )
  70. {
  71. PWSTR pEnd;
  72. WCHAR c;
  73. BOOL FirstComponent = TRUE;
  74. while(*VariableValue) {
  75. //
  76. // Find the termination of the current component,
  77. // which is either a ; or 0.
  78. //
  79. pEnd = wcschr(VariableValue,L';');
  80. if(!pEnd) {
  81. pEnd = wcschr(VariableValue,0);
  82. }
  83. c = *pEnd;
  84. *pEnd = 0;
  85. wprintf(
  86. L"%s%s %s\n",
  87. FirstComponent ? VariableName : L" ",
  88. FirstComponent ? L":" : L" ",
  89. VariableValue
  90. );
  91. *pEnd = c;
  92. VariableValue = pEnd + (c ? 1 : 0);
  93. FirstComponent = FALSE;
  94. }
  95. }
  96. VOID
  97. RotateNvRamVariable(
  98. IN PWSTR VariableValue
  99. )
  100. {
  101. PWSTR pEnd;
  102. WCHAR Buffer[32768];
  103. //
  104. // Find the termination of the current component,
  105. // which is either a ; or 0.
  106. //
  107. pEnd = wcschr(VariableValue,L';');
  108. if(!pEnd) {
  109. pEnd = wcschr(VariableValue,0);
  110. }
  111. //
  112. // Copy VariableValue into Buffer starting at second entry
  113. //
  114. wcscpy(Buffer, pEnd + (*pEnd ? 1 : 0));
  115. //
  116. // Append first entry at the end of Buffer
  117. //
  118. if (*pEnd) wcscpy(Buffer + wcslen(Buffer), L";");
  119. *pEnd = 0;
  120. wcscpy(Buffer + wcslen(Buffer), VariableValue);
  121. //
  122. // Copy whole thing back into VariableValue
  123. //
  124. wcscpy(VariableValue, Buffer);
  125. }
  126. int _cdecl main(
  127. IN int argc,
  128. IN char *argv[]
  129. )
  130. {
  131. DWORD var;
  132. UNICODE_STRING UnicodeString;
  133. NTSTATUS Status;
  134. BOOLEAN OldPriv;
  135. WCHAR Buffer[32768];
  136. WCHAR Buffer1[32768];
  137. WCHAR Buffer2[32768];
  138. Status = RtlAdjustPrivilege(
  139. SE_SYSTEM_ENVIRONMENT_PRIVILEGE,
  140. TRUE,
  141. FALSE,
  142. &OldPriv
  143. );
  144. if(!NT_SUCCESS(Status)) {
  145. wprintf(L"Insufficient privilege.\n");
  146. return(0);
  147. }
  148. if(argc == 1) {
  149. for(var=0; var<BootVarMax; var++) {
  150. RtlInitUnicodeString(&UnicodeString,BootVarNames[var]);
  151. Status = NtQuerySystemEnvironmentValue(
  152. &UnicodeString,
  153. Buffer,
  154. SIZECHARS(Buffer),
  155. NULL
  156. );
  157. if(NT_SUCCESS(Status)) {
  158. PrintNvRamVariable(PaddedBootVarNames[var],Buffer);
  159. } else {
  160. wprintf(L"%s: <empty>\n",PaddedBootVarNames[var]);
  161. }
  162. wprintf(L"\n");
  163. }
  164. }
  165. if((argc == 2) && !lstrcmpiA(argv[1],"rotate")){
  166. for(var=0; var<BootVarMax; var++) {
  167. RtlInitUnicodeString(&UnicodeString,BootVarNames[var]);
  168. Status = NtQuerySystemEnvironmentValue(
  169. &UnicodeString,
  170. Buffer,
  171. SIZECHARS(Buffer),
  172. NULL
  173. );
  174. if(NT_SUCCESS(Status)) {
  175. RotateNvRamVariable(Buffer);
  176. printf(
  177. "Setting variable %ws to %ws [%s]\n",
  178. UnicodeString.Buffer,
  179. Buffer,
  180. DoSetNvRamVar(UnicodeString.Buffer,Buffer) ? "OK" : "Error"
  181. );
  182. } else {
  183. wprintf(L"%s: <empty>\n",PaddedBootVarNames[var]);
  184. }
  185. wprintf(L"\n");
  186. }
  187. }
  188. if((argc == 5) && !lstrcmpiA(argv[1]+1,"set") && !lstrcmpA(argv[3],"=")) {
  189. MultiByteToWideChar(
  190. CP_OEMCP,
  191. MB_PRECOMPOSED,
  192. argv[2],
  193. -1,
  194. Buffer1,
  195. SIZECHARS(Buffer1)
  196. );
  197. MultiByteToWideChar(
  198. CP_OEMCP,
  199. MB_PRECOMPOSED,
  200. argv[4],
  201. -1,
  202. Buffer2,
  203. SIZECHARS(Buffer2)
  204. );
  205. printf(
  206. "Setting variable %ws to %ws [%s]\n",
  207. Buffer1,
  208. Buffer2,
  209. DoSetNvRamVar(Buffer1,Buffer2) ? "OK" : "Error"
  210. );
  211. }
  212. return(0);
  213. }
  214. #else
  215. TCHAR LoadID[500]; // load identifier (no quotes)
  216. TCHAR CountDown[100]; // countdown timer
  217. TCHAR OsLoadOptions[500]; // load options
  218. TCHAR OsName[500]; // name of default os
  219. TCHAR OsLine[500]; // complete line of os description and options
  220. #define STR_BOOTINI TEXT("c:\\boot.ini")
  221. #define STR_BOOTLDR TEXT("boot loader")
  222. #define STR_TIMEOUT TEXT("timeout")
  223. #define STR_DEFAULT TEXT("default")
  224. #define STR_OPERATINGSYS TEXT("operating systems")
  225. #define STR_NULL TEXT("")
  226. //
  227. // HandleOption - add option to OsLoadOptions
  228. //
  229. VOID HandleOption( TCHAR* Option )
  230. {
  231. TCHAR SlashOption[200];
  232. TCHAR SlashOptionSlash[200];
  233. //
  234. // find out if option already exists
  235. // add blank to end to prevent debug from matching debugport
  236. //
  237. wsprintf( SlashOption, TEXT("/%s "), Option );
  238. wsprintf( SlashOptionSlash, TEXT("/%s/"), Option );
  239. if( wcsstr( OsLoadOptions, SlashOption ) ||
  240. wcsstr( OsLoadOptions, SlashOptionSlash ) )
  241. {
  242. printf("option already exists: %ws\n",Option);
  243. }
  244. else
  245. {
  246. //
  247. // append option without the trailing blank
  248. //
  249. printf("added option %ws\n",Option);
  250. lstrcat( OsLoadOptions, TEXT("/") );
  251. lstrcat( OsLoadOptions, Option );
  252. }
  253. }
  254. //
  255. // WriteBootIni - update the boot.ini file with our changes
  256. //
  257. VOID WriteBootIni()
  258. {
  259. DWORD FileAttr;
  260. //
  261. // Get file attributes of boot.ini for later restoration
  262. //
  263. FileAttr= GetFileAttributes( STR_BOOTINI );
  264. //
  265. // Change file attributes on boot.ini so we can write to it.
  266. //
  267. if( !SetFileAttributes( STR_BOOTINI, FILE_ATTRIBUTE_NORMAL ) )
  268. {
  269. printf("Failed to turn off read-only on boot.ini (lasterr= %d)\n",
  270. GetLastError() );
  271. }
  272. //
  273. // Update boot.ini strings
  274. //
  275. if( !WritePrivateProfileString( STR_BOOTLDR, STR_TIMEOUT,
  276. CountDown, STR_BOOTINI ) )
  277. {
  278. printf("failed to write timeout (lasterr= %d)\n",GetLastError());
  279. }
  280. //
  281. // create the osline from its parts
  282. //
  283. wsprintf(OsLine, TEXT("\"%s\"%s"), LoadID, OsLoadOptions );
  284. if( !WritePrivateProfileString( STR_OPERATINGSYS, OsName,
  285. OsLine, STR_BOOTINI ) )
  286. {
  287. printf("failed to write OS line (lasterr= %d)\n",GetLastError());
  288. }
  289. //
  290. // Restore boot.ini file attributes
  291. //
  292. if( FileAttr != 0xFFFFFFFF )
  293. {
  294. SetFileAttributes( STR_BOOTINI, FileAttr );
  295. }
  296. }
  297. //
  298. // Usage - print out usage information
  299. //
  300. VOID Usage()
  301. {
  302. printf("\nUsage:\n");
  303. printf(" no parameters: prints current settings.\n");
  304. printf(" /set parameter = value : sets value in boot.ini\n");
  305. printf(" rotate : rotates default build through boot options\n");
  306. printf("\n");
  307. printf("Example: nvram /set osloadoptions = debug\n");
  308. printf(" This will set the debug option on\n\n");
  309. printf("Available options:\n");
  310. printf(" loadidentifier, osloadoptions, countdown\n");
  311. }
  312. int _cdecl main(
  313. IN int argc,
  314. IN char *argv[]
  315. )
  316. {
  317. DWORD dwStatus;
  318. LPWSTR* pArgs;
  319. // parse command line in unicode
  320. pArgs= CommandLineToArgvW( GetCommandLine(), &argc );
  321. //
  322. // Get the boot information from boot.ini
  323. //
  324. // timeout
  325. dwStatus= GetPrivateProfileString(
  326. STR_BOOTLDR,
  327. STR_TIMEOUT,
  328. STR_NULL,
  329. CountDown,
  330. SIZECHARS(CountDown),
  331. STR_BOOTINI );
  332. if( !dwStatus )
  333. {
  334. printf("Failed to get timeout value\n");
  335. return(-1);
  336. }
  337. // default os description and options
  338. dwStatus= GetPrivateProfileString(
  339. STR_BOOTLDR,
  340. STR_DEFAULT,
  341. STR_NULL,
  342. OsName,
  343. SIZECHARS(OsName),
  344. STR_BOOTINI );
  345. if( !dwStatus )
  346. {
  347. printf("Failed to get default OS name\n");
  348. return(-1);
  349. }
  350. dwStatus= GetPrivateProfileString(
  351. STR_OPERATINGSYS,
  352. OsName,
  353. STR_NULL,
  354. OsLine,
  355. SIZECHARS(OsLine),
  356. STR_BOOTINI );
  357. if( !dwStatus )
  358. {
  359. printf("Failed to get default os description\n");
  360. return(-1);
  361. }
  362. //
  363. // Now parse the line into description and options.
  364. // If it starts with a quote, it may have options.
  365. // If it doesn't start with a quote, it won't.
  366. //
  367. *LoadID= *OsLoadOptions= TEXT('\0');
  368. if( *OsLine == TEXT('"') )
  369. {
  370. INT i;
  371. for( i=1; OsLine[i]; i++ )
  372. {
  373. LoadID[i-1]= OsLine[i];
  374. if( OsLine[i] == TEXT('"') )
  375. break;
  376. }
  377. if( OsLine[i] )
  378. {
  379. LoadID[i-1]= TEXT('\0'); // don't copy final quote
  380. lstrcpy( OsLoadOptions, &OsLine[i+1] );
  381. lstrcat( OsLoadOptions, TEXT(" ") ); // all options end with blank
  382. }
  383. }
  384. else
  385. {
  386. lstrcpy( LoadID, OsLine );
  387. lstrcpy( OsLoadOptions, TEXT("") );
  388. }
  389. // no parameters prints out values
  390. if( argc == 1 )
  391. {
  392. printf("%ws: %ws\n",PaddedBootVarNames[BootVarLoadIdentifier], LoadID);
  393. printf("%ws: %ws\n",PaddedBootVarNames[BootVarOsLoadOptions], OsLoadOptions);
  394. printf("%ws: %ws\n",PaddedBootVarNames[BootVarCountdown], CountDown);
  395. }
  396. // -set parameter = value
  397. // sets parameter to some value
  398. if( (argc == 2) &&
  399. !lstrcmpiW(pArgs[1],L"rotate") )
  400. {
  401. INT i;
  402. DWORD FileAttr;
  403. //
  404. // Read in all boot options
  405. //
  406. dwStatus= GetPrivateProfileString(
  407. STR_OPERATINGSYS,
  408. NULL,
  409. STR_NULL,
  410. OsLine,
  411. SIZECHARS(OsLine),
  412. STR_BOOTINI );
  413. if( !dwStatus )
  414. {
  415. printf("Failed to get os section\n");
  416. return(-1);
  417. }
  418. //
  419. // read through boot options until we find default entry
  420. //
  421. i = 0;
  422. while( lstrcmpiW( OsName, &(OsLine[i]) ) ){
  423. i = i + wcslen(&OsLine[i]) + 1;
  424. }
  425. //
  426. // increment one more entry
  427. //
  428. i = i + wcslen(&OsLine[i]) + 1;
  429. //
  430. // if we've gone off the end then start over
  431. //
  432. if (!lstrcmpiW( &(OsLine[i]), L"\0\0" ) ){
  433. i = 0;
  434. }
  435. //
  436. // Get file attributes of boot.ini for later restoration
  437. //
  438. FileAttr= GetFileAttributes( STR_BOOTINI );
  439. //
  440. // Change file attributes on boot.ini so we can write to it.
  441. //
  442. if( !SetFileAttributes( STR_BOOTINI, FILE_ATTRIBUTE_NORMAL ) )
  443. {
  444. printf("Failed to turn off read-only on boot.ini (lasterr= %d)\n",
  445. GetLastError() );
  446. }
  447. if( !WritePrivateProfileString( STR_BOOTLDR, STR_DEFAULT,
  448. &(OsLine[i]), STR_BOOTINI ) )
  449. {
  450. printf("failed to write default (lasterr= %d)\n",GetLastError());
  451. }
  452. //
  453. // Restore boot.ini file attributes
  454. //
  455. if( FileAttr != 0xFFFFFFFF )
  456. {
  457. SetFileAttributes( STR_BOOTINI, FileAttr );
  458. }
  459. }
  460. if( (argc == 5) &&
  461. !lstrcmpiW(pArgs[1]+1,L"set") &&
  462. !lstrcmpW(pArgs[3],L"=") )
  463. {
  464. INT i;
  465. // see if we understand parameter
  466. for( i=0; i<BootVarMax; i++ )
  467. {
  468. if( lstrcmpiW( pArgs[2], BootVarNames[i] ) == 0 )
  469. break;
  470. }
  471. // handle the ones we can
  472. switch( i )
  473. {
  474. default:
  475. printf("Not valid parameter name to set: %ws\n",pArgs[2]);
  476. Usage();
  477. return(-1);
  478. break;
  479. case BootVarLoadIdentifier:
  480. lstrcpyW( LoadID, pArgs[4] );
  481. break;
  482. case BootVarOsLoadOptions:
  483. HandleOption( pArgs[4] );
  484. break;
  485. case BootVarCountdown:
  486. lstrcpyW( CountDown, pArgs[4] );
  487. break;
  488. }
  489. WriteBootIni();
  490. }
  491. // -?
  492. // usage message
  493. if( argc == 2 && !lstrcmpW(pArgs[1]+1, L"?") )
  494. {
  495. Usage();
  496. }
  497. return(0);
  498. }
  499. #endif