config.c 26 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299
  1. /*++
  2. Copyright (c) 2016 Minoca Corp.
  3. This file is licensed under the terms of the GNU General Public License
  4. version 3. Alternative licensing terms are available. Contact
  5. info@minocacorp.com for details. See the LICENSE file at the root of this
  6. project for complete licensing information.
  7. Module Name:
  8. config.c
  9. Abstract:
  10. This module implements the interface to the Chalk interpreter used to
  11. gather the configuration together.
  12. Author:
  13. Evan Green 21-Oct-2016
  14. Environment:
  15. User
  16. --*/
  17. //
  18. // ------------------------------------------------------------------- Includes
  19. //
  20. #include <assert.h>
  21. #include <errno.h>
  22. #include <fcntl.h>
  23. #include <stdio.h>
  24. #include <stdlib.h>
  25. #include <string.h>
  26. #include <sys/stat.h>
  27. #include <time.h>
  28. #include "setup.h"
  29. #include "sconf.h"
  30. //
  31. // ---------------------------------------------------------------- Definitions
  32. //
  33. //
  34. // ------------------------------------------------------ Data Type Definitions
  35. //
  36. //
  37. // ----------------------------------------------- Internal Function Prototypes
  38. //
  39. VOID
  40. SetupChalkModuleInitialize (
  41. PCK_VM Vm
  42. );
  43. INT
  44. SetupReadBootConfiguration (
  45. PCK_VM Vm,
  46. PSETUP_CONFIGURATION Configuration
  47. );
  48. INT
  49. SetupReadBootEntry (
  50. PCK_VM Vm,
  51. PBOOT_ENTRY BootEntry
  52. );
  53. INT
  54. SetupReadDiskConfiguration (
  55. PCK_VM Vm,
  56. PSETUP_DISK_CONFIGURATION Disk
  57. );
  58. INT
  59. SetupReadPartitionConfiguration (
  60. PCK_VM Vm,
  61. PSETUP_PARTITION_CONFIGURATION Partition
  62. );
  63. PCSTR *
  64. SetupReadStringsList (
  65. PCK_VM Vm
  66. );
  67. INT
  68. SetupReadCopy (
  69. PCK_VM Vm,
  70. PSETUP_COPY Copy
  71. );
  72. BOOL
  73. SetupDictGet (
  74. PCK_VM Vm,
  75. INTN StackIndex,
  76. PSTR Key
  77. );
  78. int
  79. SetupComparePartitionConfigurations (
  80. const void *LeftPointer,
  81. const void *RightPointer
  82. );
  83. VOID
  84. SetupDestroyCopyCommand (
  85. PSETUP_COPY Copy
  86. );
  87. //
  88. // -------------------------------------------------------------------- Globals
  89. //
  90. //
  91. // ------------------------------------------------------------------ Functions
  92. //
  93. INT
  94. SetupLoadConfiguration (
  95. PSETUP_CONTEXT Context
  96. )
  97. /*++
  98. Routine Description:
  99. This routine prepares to run the configuration specialization script.
  100. Arguments:
  101. Context - Supplies a pointer to the application context.
  102. Return Value:
  103. 0 on success.
  104. Returns a non-zero value on failure.
  105. --*/
  106. {
  107. PVOID Buffer;
  108. ssize_t BytesRead;
  109. PVOID File;
  110. BOOL Result;
  111. ULONGLONG Size;
  112. INT Status;
  113. Buffer = NULL;
  114. File = NULL;
  115. assert((Context->PlatformName != NULL) && (Context->ArchName != NULL) &&
  116. (Context->SourceVolume != NULL));
  117. CkSetContext(Context->ChalkVm, Context);
  118. Result = CkPreloadForeignModule(Context->ChalkVm,
  119. "msetup",
  120. NULL,
  121. NULL,
  122. SetupChalkModuleInitialize);
  123. if (Result == FALSE) {
  124. return -1;
  125. }
  126. //
  127. // Open up the install configuration script in the image.
  128. //
  129. File = SetupFileOpen(Context->SourceVolume,
  130. SETUP_CONFIGURATION_PATH,
  131. O_RDONLY | O_BINARY,
  132. 0);
  133. if (File == NULL) {
  134. fprintf(stderr,
  135. "msetup: Failed to open configuration %s\n",
  136. SETUP_CONFIGURATION_PATH);
  137. Status = -1;
  138. goto LoadConfigurationEnd;
  139. }
  140. Size = 0;
  141. Status = SetupFileFileStat(File, &Size, NULL, NULL);
  142. if (Status != 0) {
  143. goto LoadConfigurationEnd;
  144. }
  145. Buffer = malloc(Size);
  146. if (Buffer == NULL) {
  147. goto LoadConfigurationEnd;
  148. }
  149. BytesRead = SetupFileRead(File, Buffer, Size);
  150. if (BytesRead != Size) {
  151. Status = -1;
  152. goto LoadConfigurationEnd;
  153. }
  154. //
  155. // Execute the script.
  156. //
  157. Status = CkInterpret(Context->ChalkVm, NULL, Buffer, Size, 1, FALSE);
  158. if (Status != CkSuccess) {
  159. fprintf(stderr,
  160. "msetup: Failed to execute configuration script: %d\n",
  161. Status);
  162. Status = EINVAL;
  163. goto LoadConfigurationEnd;
  164. }
  165. LoadConfigurationEnd:
  166. if (File != NULL) {
  167. SetupFileClose(File);
  168. }
  169. if (Buffer != NULL) {
  170. free(Buffer);
  171. }
  172. return Status;
  173. }
  174. INT
  175. SetupLoadUserScript (
  176. PSETUP_CONTEXT Context,
  177. PCSTR Path
  178. )
  179. /*++
  180. Routine Description:
  181. This routine loads and runs a user customization script in the setup app.
  182. Arguments:
  183. Context - Supplies a pointer to the application context.
  184. Path - Supplies a pointer to the path of the custom script to run.
  185. Return Value:
  186. 0 on success.
  187. Returns a non-zero value on failure.
  188. --*/
  189. {
  190. PSTR Buffer;
  191. FILE *File;
  192. struct stat Stat;
  193. INT Status;
  194. Buffer = NULL;
  195. File = NULL;
  196. if (stat(Path, &Stat) != 0) {
  197. return errno;
  198. }
  199. File = fopen(Path, "rb");
  200. if (File == NULL) {
  201. return errno;
  202. }
  203. Buffer = malloc(Stat.st_size + 1);
  204. if (Buffer == NULL) {
  205. Status = errno;
  206. goto LoadUserScriptEnd;
  207. }
  208. if (fread(Buffer, 1, Stat.st_size, File) != Stat.st_size) {
  209. Status = errno;
  210. goto LoadUserScriptEnd;
  211. }
  212. Buffer[Stat.st_size] = '\0';
  213. Status = CkInterpret(Context->ChalkVm,
  214. Path,
  215. Buffer,
  216. Stat.st_size,
  217. 1,
  218. FALSE);
  219. if (Status != CkSuccess) {
  220. fprintf(stderr, "Failed to interpret script %s: %d\n", Path, Status);
  221. Status = -1;
  222. goto LoadUserScriptEnd;
  223. }
  224. Status = 0;
  225. LoadUserScriptEnd:
  226. if (File != NULL) {
  227. fclose(File);
  228. }
  229. if (Buffer != NULL) {
  230. free(Buffer);
  231. }
  232. return Status;
  233. }
  234. INT
  235. SetupLoadUserExpression (
  236. PSETUP_CONTEXT Context,
  237. PCSTR Expression
  238. )
  239. /*++
  240. Routine Description:
  241. This routine runs a user customization script expression in the setup app.
  242. Arguments:
  243. Context - Supplies a pointer to the application context.
  244. Expression - Supplies a pointer to the script fragment to evaluate.
  245. Return Value:
  246. 0 on success.
  247. Returns a non-zero value on failure.
  248. --*/
  249. {
  250. INT Status;
  251. Status = CkInterpret(Context->ChalkVm,
  252. NULL,
  253. Expression,
  254. strlen(Expression),
  255. 1,
  256. FALSE);
  257. if (Status != CkSuccess) {
  258. fprintf(stderr,
  259. "Failed to evaluate expression: %s\nError: %d\n",
  260. Expression,
  261. Status);
  262. return -1;
  263. }
  264. return 0;
  265. }
  266. INT
  267. SetupReadConfiguration (
  268. PCK_VM Vm,
  269. PSETUP_CONFIGURATION *NewConfiguration
  270. )
  271. /*++
  272. Routine Description:
  273. This routine reads the configuration into the given setup context after the
  274. interpreter has finished running.
  275. Arguments:
  276. Vm - Supplies a pointer to the Chalk virtual machine.
  277. NewConfiguration - Supplies a pointer where a pointer to the new
  278. configuration will be returned on success.
  279. Return Value:
  280. 0 on success.
  281. EINVAL on configuration errors.
  282. Other errors on other failures.
  283. --*/
  284. {
  285. PSETUP_CONFIGURATION Configuration;
  286. INT Status;
  287. Configuration = malloc(sizeof(SETUP_CONFIGURATION));
  288. if (Configuration == NULL) {
  289. Status = ENOMEM;
  290. goto ReadConfigurationEnd;
  291. }
  292. memset(Configuration, 0, sizeof(SETUP_CONFIGURATION));
  293. if (!CkEnsureStack(Vm, 50)) {
  294. Status = ENOMEM;
  295. goto ReadConfigurationEnd;
  296. }
  297. CkPushModule(Vm, "__main");
  298. CkGetVariable(Vm, -1, "Settings");
  299. if (CkIsNull(Vm, -1)) {
  300. fprintf(stderr, "Error: No settings found.\n");
  301. Status = EINVAL;
  302. goto ReadConfigurationEnd;
  303. }
  304. if (SetupDictGet(Vm, -1, "BootConfiguration") != FALSE) {
  305. Status = SetupReadBootConfiguration(Vm, Configuration);
  306. if (Status != 0) {
  307. goto ReadConfigurationEnd;
  308. }
  309. CkStackPop(Vm);
  310. }
  311. if (!SetupDictGet(Vm, -1, "Disk")) {
  312. fprintf(stderr, "Error: No disk configuration found.\n");
  313. Status = EINVAL;
  314. goto ReadConfigurationEnd;
  315. }
  316. Status = SetupReadDiskConfiguration(Vm, &(Configuration->Disk));
  317. CkStackPop(Vm);
  318. if (Status != 0) {
  319. goto ReadConfigurationEnd;
  320. }
  321. //
  322. // Get the driver database.
  323. //
  324. if (SetupDictGet(Vm, -1, "DriverDb")) {
  325. if (SetupDictGet(Vm, -1, "BootDrivers")) {
  326. Configuration->BootDrivers = SetupReadStringsList(Vm);
  327. if (Configuration->BootDrivers == NULL) {
  328. Status = EINVAL;
  329. goto ReadConfigurationEnd;
  330. }
  331. CkStackPop(Vm);
  332. }
  333. if (SetupDictGet(Vm, -1, "BootDriversPath")) {
  334. Configuration->BootDriversPath = CkGetString(Vm, -1, NULL);
  335. CkStackPop(Vm);
  336. }
  337. CkStackPop(Vm);
  338. }
  339. CkStackPop(Vm);
  340. CkStackPop(Vm);
  341. Status = 0;
  342. ReadConfigurationEnd:
  343. if (Status != 0) {
  344. if (Configuration != NULL) {
  345. SetupDestroyConfiguration(Configuration);
  346. Configuration = NULL;
  347. }
  348. }
  349. *NewConfiguration = Configuration;
  350. return Status;
  351. }
  352. VOID
  353. SetupDestroyConfiguration (
  354. PSETUP_CONFIGURATION Configuration
  355. )
  356. /*++
  357. Routine Description:
  358. This routine destroys a setup configuration.
  359. Arguments:
  360. Configuration - Supplies a pointer to the configuration to destroy.
  361. Return Value:
  362. None.
  363. --*/
  364. {
  365. ULONG CopyIndex;
  366. PSETUP_DISK_CONFIGURATION Disk;
  367. ULONG Index;
  368. PSETUP_PARTITION_CONFIGURATION Partition;
  369. Configuration->BootDriversPath = NULL;
  370. if (Configuration->BootDrivers != NULL) {
  371. free(Configuration->BootDrivers);
  372. Configuration->BootDrivers = NULL;
  373. }
  374. if (Configuration->BootEntries != NULL) {
  375. free(Configuration->BootEntries);
  376. Configuration->BootEntries = NULL;
  377. }
  378. Configuration->BootEntryCount = 0;
  379. Disk = &(Configuration->Disk);
  380. SetupDestroyCopyCommand(&(Disk->Mbr));
  381. for (Index = 0; Index < Disk->PartitionCount; Index += 1) {
  382. Partition = &(Disk->Partitions[Index]);
  383. SetupDestroyCopyCommand(&(Partition->Vbr));
  384. for (CopyIndex = 0;
  385. CopyIndex < Partition->CopyCommandCount;
  386. CopyIndex += 1) {
  387. SetupDestroyCopyCommand(&(Partition->CopyCommands[CopyIndex]));
  388. }
  389. if (Partition->CopyCommands != NULL) {
  390. free(Partition->CopyCommands);
  391. Partition->CopyCommands = NULL;
  392. }
  393. Partition->CopyCommandCount = 0;
  394. }
  395. free(Configuration);
  396. return;
  397. }
  398. //
  399. // --------------------------------------------------------- Internal Functions
  400. //
  401. VOID
  402. SetupChalkModuleInitialize (
  403. PCK_VM Vm
  404. )
  405. /*++
  406. Routine Description:
  407. This routine initializes the msetup module planted in the Chalk interpreter.
  408. Arguments:
  409. Vm - Supplies a pointer to the virtual machine.
  410. Return Value:
  411. None. The return value of the function should be in the first stack slot.
  412. --*/
  413. {
  414. PSETUP_CONTEXT Context;
  415. Context = CkGetContext(Vm);
  416. //
  417. // Set the global variables in the module in the Chalk environment.
  418. //
  419. CkPushString(Vm, Context->ArchName, strlen(Context->ArchName));
  420. CkSetVariable(Vm, 0, "arch");
  421. CkPushString(Vm, Context->PlatformName, strlen(Context->PlatformName));
  422. CkSetVariable(Vm, 0, "plat");
  423. return;
  424. }
  425. INT
  426. SetupReadBootConfiguration (
  427. PCK_VM Vm,
  428. PSETUP_CONFIGURATION Configuration
  429. )
  430. /*++
  431. Routine Description:
  432. This routine reads the boot configuration at the top of the Chalk stack
  433. into the C structures.
  434. Arguments:
  435. Vm - Supplies a pointer to the Chalk virtual machine.
  436. Configuration - Supplies a pointer to the configuration to read into.
  437. Return Value:
  438. 0 on success.
  439. Returns an error number on failure.
  440. --*/
  441. {
  442. UINTN AllocationSize;
  443. PBOOT_ENTRY BootEntry;
  444. CK_INTEGER Count;
  445. UINTN Index;
  446. INT Status;
  447. //
  448. // Convert the global configuration first (timeout, etc).
  449. //
  450. if (SetupDictGet(Vm, -1, "Timeout")) {
  451. Configuration->GlobalBootConfiguration.Timeout = CkGetInteger(Vm, -1);
  452. CkStackPop(Vm);
  453. }
  454. if (!SetupDictGet(Vm, -1, "BootEntries")) {
  455. fprintf(stderr, "Error: No boot entries found.\n");
  456. Status = EINVAL;
  457. goto ReadBootConfigurationEnd;
  458. }
  459. if (!CkGetLength(Vm, -1, &Count)) {
  460. Status = EINVAL;
  461. goto ReadBootConfigurationEnd;
  462. }
  463. AllocationSize = sizeof(BOOT_ENTRY) * Count;
  464. Configuration->BootEntries = malloc(AllocationSize);
  465. if (Configuration->BootEntries == NULL) {
  466. Status = ENOMEM;
  467. goto ReadBootConfigurationEnd;
  468. }
  469. memset(Configuration->BootEntries, 0, AllocationSize);
  470. for (Index = 0; Index < Count; Index += 1) {
  471. BootEntry = &(Configuration->BootEntries[Index]);
  472. CkListGet(Vm, -1, Index);
  473. Status = SetupReadBootEntry(Vm, BootEntry);
  474. CkStackPop(Vm);
  475. if (Status != 0) {
  476. fprintf(stderr, "Error: Failed to read boot entry.\n");
  477. goto ReadBootConfigurationEnd;
  478. }
  479. }
  480. CkStackPop(Vm);
  481. Configuration->BootEntryCount = Count;
  482. if (SetupDictGet(Vm, -1, "DataPath")) {
  483. Configuration->BootDataPath = CkGetString(Vm, -1, NULL);
  484. CkStackPop(Vm);
  485. }
  486. ReadBootConfigurationEnd:
  487. return Status;
  488. }
  489. INT
  490. SetupReadBootEntry (
  491. PCK_VM Vm,
  492. PBOOT_ENTRY BootEntry
  493. )
  494. /*++
  495. Routine Description:
  496. This routine reads a boot entry at the top of the Chalk stack into the C
  497. structure.
  498. Arguments:
  499. Vm - Supplies a pointer to the Chalk virtual machine.
  500. BootEntry - Supplies a pointer where the boot entry information will be
  501. returned.
  502. Return Value:
  503. 0 on success.
  504. Returns an error number on failure.
  505. --*/
  506. {
  507. UINTN Size;
  508. PCSTR String;
  509. if (SetupDictGet(Vm, -1, "DiskId")) {
  510. String = CkGetString(Vm, -1, &Size);
  511. if (Size > sizeof(BootEntry->DiskId)) {
  512. Size = sizeof(BootEntry->DiskId);
  513. }
  514. memcpy(BootEntry->DiskId, String, Size);
  515. CkStackPop(Vm);
  516. }
  517. if (SetupDictGet(Vm, -1, "PartitionId")) {
  518. String = CkGetString(Vm, -1, &Size);
  519. if (Size > sizeof(BootEntry->PartitionId)) {
  520. Size = sizeof(BootEntry->PartitionId);
  521. }
  522. memcpy(BootEntry->PartitionId, String, Size);
  523. CkStackPop(Vm);
  524. }
  525. if (SetupDictGet(Vm, -1, "Name")) {
  526. BootEntry->Name = CkGetString(Vm, -1, NULL);
  527. CkStackPop(Vm);
  528. }
  529. if (SetupDictGet(Vm, -1, "LoaderArguments")) {
  530. BootEntry->LoaderArguments = CkGetString(Vm, -1, NULL);
  531. CkStackPop(Vm);
  532. }
  533. if (SetupDictGet(Vm, -1, "KernelArguments")) {
  534. BootEntry->KernelArguments = CkGetString(Vm, -1, NULL);
  535. CkStackPop(Vm);
  536. }
  537. if (SetupDictGet(Vm, -1, "LoaderPath")) {
  538. BootEntry->LoaderPath = CkGetString(Vm, -1, NULL);
  539. CkStackPop(Vm);
  540. }
  541. if (SetupDictGet(Vm, -1, "KernelPath")) {
  542. BootEntry->KernelPath = CkGetString(Vm, -1, NULL);
  543. CkStackPop(Vm);
  544. }
  545. if (SetupDictGet(Vm, -1, "SystemPath")) {
  546. BootEntry->SystemPath = CkGetString(Vm, -1, NULL);
  547. CkStackPop(Vm);
  548. }
  549. if (SetupDictGet(Vm, -1, "Flags")) {
  550. if (!CkIsDict(Vm, -1)) {
  551. fprintf(stderr, "BootEntry flags should be a dict.\n");
  552. return EINVAL;
  553. }
  554. if (SetupDictGet(Vm, -1, "Debug")) {
  555. if (CkGetInteger(Vm, -1) != FALSE) {
  556. BootEntry->Flags |= BOOT_ENTRY_FLAG_DEBUG;
  557. }
  558. CkStackPop(Vm);
  559. }
  560. if (SetupDictGet(Vm, -1, "BootDebug")) {
  561. if (CkGetInteger(Vm, -1) != FALSE) {
  562. BootEntry->Flags |= BOOT_ENTRY_FLAG_BOOT_DEBUG;
  563. }
  564. CkStackPop(Vm);
  565. }
  566. CkStackPop(Vm);
  567. }
  568. if (SetupDictGet(Vm, -1, "DebugDevice")) {
  569. BootEntry->DebugDevice = CkGetInteger(Vm, -1);
  570. CkStackPop(Vm);
  571. }
  572. return 0;
  573. }
  574. INT
  575. SetupReadDiskConfiguration (
  576. PCK_VM Vm,
  577. PSETUP_DISK_CONFIGURATION Disk
  578. )
  579. /*++
  580. Routine Description:
  581. This routine reads the disk configuration at the top of the Chalk stack
  582. into the C structures.
  583. Arguments:
  584. Vm - Supplies a pointer to the Chalk virtual machine.
  585. Disk - Supplies a pointer to the disk configuration to read into.
  586. Return Value:
  587. 0 on success.
  588. Returns an error number on failure.
  589. --*/
  590. {
  591. UINTN AllocationSize;
  592. CK_INTEGER Count;
  593. UINTN Index;
  594. INT Status;
  595. if (!SetupDictGet(Vm, -1, "Format")) {
  596. fprintf(stderr, "Error: Missing disk format.\n");
  597. return EINVAL;
  598. }
  599. Disk->PartitionFormat = CkGetInteger(Vm, -1);
  600. CkStackPop(Vm);
  601. if (SetupDictGet(Vm, -1, "Mbr")) {
  602. Status = SetupReadCopy(Vm, &(Disk->Mbr));
  603. if (Status != 0) {
  604. return Status;
  605. }
  606. CkStackPop(Vm);
  607. }
  608. if (!SetupDictGet(Vm, -1, "Partitions")) {
  609. fprintf(stderr, "Error: No partition configuration found.\n");
  610. return EINVAL;
  611. }
  612. if ((!CkIsList(Vm, -1)) || (!CkGetLength(Vm, -1, &Count))) {
  613. fprintf(stderr, "Error: Invalid partition configuration.\n");
  614. return EINVAL;
  615. }
  616. AllocationSize = sizeof(SETUP_PARTITION_CONFIGURATION) * Count;
  617. Disk->Partitions = malloc(AllocationSize);
  618. if (Disk->Partitions == NULL) {
  619. return ENOMEM;
  620. }
  621. memset(Disk->Partitions, 0, AllocationSize);
  622. for (Index = 0; Index < Count; Index += 1) {
  623. CkListGet(Vm, -1, Index);
  624. if (!CkIsDict(Vm, -1)) {
  625. fprintf(stderr,
  626. "Error: Partition configuration should be a dictionary.\n");
  627. return EINVAL;
  628. }
  629. Status = SetupReadPartitionConfiguration(Vm,
  630. &(Disk->Partitions[Index]));
  631. if (Status != 0) {
  632. fprintf(stderr,
  633. "Error: Failed to read partition %d configuration.\n",
  634. (int)Index);
  635. return Status;
  636. }
  637. CkStackPop(Vm);
  638. }
  639. Disk->PartitionCount = Count;
  640. //
  641. // Sort the partitions by index.
  642. //
  643. qsort(Disk->Partitions,
  644. Count,
  645. sizeof(SETUP_PARTITION_CONFIGURATION),
  646. SetupComparePartitionConfigurations);
  647. CkStackPop(Vm);
  648. return 0;
  649. }
  650. INT
  651. SetupReadPartitionConfiguration (
  652. PCK_VM Vm,
  653. PSETUP_PARTITION_CONFIGURATION Partition
  654. )
  655. /*++
  656. Routine Description:
  657. This routine reads the partition configuration at the top of the Chalk
  658. stack into the C structures.
  659. Arguments:
  660. Vm - Supplies a pointer to the Chalk virtual machine.
  661. Partition - Supplies a pointer to the partition configuration to read into.
  662. Return Value:
  663. 0 on success.
  664. Returns an error number on failure.
  665. --*/
  666. {
  667. UINTN AllocationSize;
  668. CK_INTEGER Count;
  669. UINTN Index;
  670. UINTN Size;
  671. INT Status;
  672. PCSTR String;
  673. if (!SetupDictGet(Vm, -1, "Index")) {
  674. fprintf(stderr, "Error: Partition index is required.\n");
  675. return EINVAL;
  676. }
  677. Partition->Index = CkGetInteger(Vm, -1);
  678. CkStackPop(Vm);
  679. if (!SetupDictGet(Vm, -1, "Size")) {
  680. fprintf(stderr, "Error: Partition size is required.\n");
  681. return EINVAL;
  682. }
  683. Partition->Size = CkGetInteger(Vm, -1);
  684. CkStackPop(Vm);
  685. if (SetupDictGet(Vm, -1, "Alignment")) {
  686. Partition->Alignment = CkGetInteger(Vm, -1);
  687. CkStackPop(Vm);
  688. }
  689. if (SetupDictGet(Vm, -1, "PartitionType")) {
  690. String = CkGetString(Vm, -1, &Size);
  691. if (Size > PARTITION_TYPE_SIZE) {
  692. Size = PARTITION_TYPE_SIZE;
  693. }
  694. memcpy(Partition->PartitionType, String, Size);
  695. CkStackPop(Vm);
  696. }
  697. if (SetupDictGet(Vm, -1, "MbrType")) {
  698. Partition->MbrType = CkGetInteger(Vm, -1);
  699. CkStackPop(Vm);
  700. }
  701. if (SetupDictGet(Vm, -1, "Attributes")) {
  702. Partition->Attributes = CkGetInteger(Vm, -1);
  703. CkStackPop(Vm);
  704. }
  705. if (SetupDictGet(Vm, -1, "Vbr")) {
  706. Status = SetupReadCopy(Vm, &(Partition->Vbr));
  707. CkStackPop(Vm);
  708. if (Status != 0) {
  709. return Status;
  710. }
  711. }
  712. if (SetupDictGet(Vm, -1, "Flags")) {
  713. if (SetupDictGet(Vm, -1, "Boot")) {
  714. if (CkGetInteger(Vm, -1) != FALSE) {
  715. Partition->Flags |= SETUP_PARTITION_FLAG_BOOT;
  716. }
  717. CkStackPop(Vm);
  718. }
  719. if (SetupDictGet(Vm, -1, "System")) {
  720. if (CkGetInteger(Vm, -1) != FALSE) {
  721. Partition->Flags |= SETUP_PARTITION_FLAG_SYSTEM;
  722. }
  723. CkStackPop(Vm);
  724. }
  725. if (SetupDictGet(Vm, -1, "CompatibilityMode")) {
  726. if (CkGetInteger(Vm, -1) != FALSE) {
  727. Partition->Flags |= SETUP_PARTITION_FLAG_COMPATIBILITY_MODE;
  728. }
  729. CkStackPop(Vm);
  730. }
  731. if (SetupDictGet(Vm, -1, "WriteVbrLba")) {
  732. if (CkGetInteger(Vm, -1) != FALSE) {
  733. Partition->Flags |= SETUP_PARTITION_FLAG_WRITE_VBR_LBA;
  734. }
  735. CkStackPop(Vm);
  736. }
  737. if (SetupDictGet(Vm, -1, "MergeVbr")) {
  738. if (CkGetInteger(Vm, -1) != FALSE) {
  739. Partition->Flags |= SETUP_PARTITION_FLAG_MERGE_VBR;
  740. }
  741. CkStackPop(Vm);
  742. }
  743. CkStackPop(Vm);
  744. }
  745. if (SetupDictGet(Vm, -1, "Files")) {
  746. if ((!CkIsList(Vm, -1)) || (!CkGetLength(Vm, -1, &Count))) {
  747. fprintf(stderr, "Error: Partition files must be a list.\n");
  748. return EINVAL;
  749. }
  750. AllocationSize = Count * sizeof(SETUP_COPY);
  751. Partition->CopyCommands = malloc(AllocationSize);
  752. if (Partition->CopyCommands == NULL) {
  753. return ENOMEM;
  754. }
  755. memset(Partition->CopyCommands, 0, AllocationSize);
  756. for (Index = 0; Index < Count; Index += 1) {
  757. CkListGet(Vm, -1, Index);
  758. Status = SetupReadCopy(Vm, &(Partition->CopyCommands[Index]));
  759. if (Status != 0) {
  760. return Status;
  761. }
  762. Partition->CopyCommandCount = Index + 1;
  763. if (SetupDictGet(Vm, -1, "Files")) {
  764. Partition->CopyCommands[Index].Files = SetupReadStringsList(Vm);
  765. if (Partition->CopyCommands[Index].Files == NULL) {
  766. return EINVAL;
  767. }
  768. CkStackPop(Vm);
  769. }
  770. CkStackPop(Vm);
  771. }
  772. CkStackPop(Vm);
  773. }
  774. return 0;
  775. }
  776. PCSTR *
  777. SetupReadStringsList (
  778. PCK_VM Vm
  779. )
  780. /*++
  781. Routine Description:
  782. This routine converts a list of strings at the top of the Chalk stack
  783. into an array of null-terminated C strings.
  784. Arguments:
  785. Vm - Supplies a pointer to the virtual machine.
  786. Return Value:
  787. Returns a pointer to an array of strings on success. The caller is
  788. responsible freeing the array itself, but not each string within it, as
  789. those are owned by Chalk.
  790. --*/
  791. {
  792. PCSTR *Array;
  793. CK_INTEGER Count;
  794. UINTN Index;
  795. if ((!CkIsList(Vm, -1)) || (!CkGetLength(Vm, -1, &Count))) {
  796. return NULL;
  797. }
  798. Array = malloc(sizeof(PCSTR) * (Count + 1));
  799. memset(Array, 0, sizeof(PCSTR) * (Count + 1));
  800. for (Index = 0; Index < Count; Index += 1) {
  801. CkListGet(Vm, -1, Index);
  802. Array[Index] = CkGetString(Vm, -1, NULL);
  803. CkStackPop(Vm);
  804. if (Array[Index] == NULL) {
  805. free(Array);
  806. return NULL;
  807. }
  808. }
  809. return Array;
  810. }
  811. INT
  812. SetupReadCopy (
  813. PCK_VM Vm,
  814. PSETUP_COPY Copy
  815. )
  816. /*++
  817. Routine Description:
  818. This routine reads a copy command at the top of the Chalk stack into the C
  819. structure.
  820. Arguments:
  821. Vm - Supplies a pointer to the Chalk virtual machine.
  822. Copy - Supplies a pointer where the filled out copy command will be
  823. returned.
  824. Return Value:
  825. 0 on success.
  826. Returns an error number on failure.
  827. --*/
  828. {
  829. if (SetupDictGet(Vm, -1, "Destination")) {
  830. Copy->Destination = CkGetString(Vm, -1, NULL);
  831. CkStackPop(Vm);
  832. }
  833. if (SetupDictGet(Vm, -1, "Offset")) {
  834. Copy->Offset = CkGetInteger(Vm, -1);
  835. CkStackPop(Vm);
  836. }
  837. if (SetupDictGet(Vm, -1, "Source")) {
  838. Copy->Source = CkGetString(Vm, -1, NULL);
  839. CkStackPop(Vm);
  840. } else {
  841. fprintf(stderr, "Error: Source field missing in copy.\n");
  842. return EINVAL;
  843. }
  844. if (SetupDictGet(Vm, -1, "SourceVolume")) {
  845. Copy->SourceVolume = CkGetInteger(Vm, -1);
  846. CkStackPop(Vm);
  847. }
  848. if (SetupDictGet(Vm, -1, "Update")) {
  849. if (CkGetInteger(Vm, -1) != FALSE) {
  850. Copy->Flags |= SETUP_COPY_FLAG_UPDATE;
  851. }
  852. CkStackPop(Vm);
  853. }
  854. if (SetupDictGet(Vm, -1, "Optional")) {
  855. if (CkGetInteger(Vm, -1) != FALSE) {
  856. Copy->Flags |= SETUP_COPY_FLAG_OPTIONAL;
  857. }
  858. CkStackPop(Vm);
  859. }
  860. return 0;
  861. }
  862. BOOL
  863. SetupDictGet (
  864. PCK_VM Vm,
  865. INTN StackIndex,
  866. PSTR Key
  867. )
  868. /*++
  869. Routine Description:
  870. This routine gets the value in a dict associated with a given string key.
  871. Arguments:
  872. Vm - Supplies a pointer to the virtual machine.
  873. StackIndex - Supplies the stack index of the dictionary.
  874. Key - Supplies the string key to use.
  875. Return Value:
  876. TRUE if the value at the key is non-null.
  877. FALSE if null was returned.
  878. --*/
  879. {
  880. CkPushString(Vm, Key, strlen(Key));
  881. if (StackIndex < 0) {
  882. StackIndex -= 1;
  883. }
  884. if (!CkDictGet(Vm, StackIndex)) {
  885. return FALSE;
  886. }
  887. return TRUE;
  888. }
  889. int
  890. SetupComparePartitionConfigurations (
  891. const void *LeftPointer,
  892. const void *RightPointer
  893. )
  894. /*++
  895. Routine Description:
  896. This routine compares two partition configurations by index for the qsort
  897. function.
  898. Arguments:
  899. LeftPointer - Supplies a pointer to the left side of the comparison.
  900. RightPointer - Supplies a pointer to the right side of the comparison.
  901. Return Value:
  902. < 0 if the partitions are in ascending order.
  903. 0 if the partitions are equal.
  904. > 0 if the partitions are in descending order.
  905. --*/
  906. {
  907. PSETUP_PARTITION_CONFIGURATION Left;
  908. PSETUP_PARTITION_CONFIGURATION Right;
  909. Left = (PSETUP_PARTITION_CONFIGURATION)LeftPointer;
  910. Right = (PSETUP_PARTITION_CONFIGURATION)RightPointer;
  911. if (Left->Index < Right->Index) {
  912. return -1;
  913. } else if (Left->Index > Right->Index) {
  914. return 1;
  915. }
  916. return 0;
  917. }
  918. VOID
  919. SetupDestroyCopyCommand (
  920. PSETUP_COPY Copy
  921. )
  922. /*++
  923. Routine Description:
  924. This routine destroys the inner contents of a setup copy command.
  925. Arguments:
  926. Copy - Supplies a pointer to the copy command to destroy.
  927. Return Value:
  928. None.
  929. --*/
  930. {
  931. if (Copy->Files != NULL) {
  932. free(Copy->Files);
  933. Copy->Files = NULL;
  934. }
  935. return;
  936. }