* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*/
+/* INCLUDES *******************************************************************/
+
#include <freeldr.h>
-#define TAG_STRING ' rtS'
+#include <debug.h>
+DBG_DEFAULT_CHANNEL(INIFILE);
+
#define TAG_OS_ITEM 'tISO'
+/* FUNCTIONS ******************************************************************/
+
static PCSTR CopyString(PCSTR Source)
{
PSTR Dest;
if (!Source)
return NULL;
+
Dest = FrLdrHeapAlloc(strlen(Source) + 1, TAG_STRING);
if (Dest)
- {
strcpy(Dest, Source);
- }
return Dest;
}
-OperatingSystemItem* InitOperatingSystemList(ULONG* OperatingSystemCountPointer)
+OperatingSystemItem*
+InitOperatingSystemList(
+ IN ULONG_PTR FrLdrSectionId,
+ OUT PULONG OperatingSystemCount,
+ OUT PULONG DefaultOperatingSystem)
{
- ULONG Idx;
- CHAR SettingName[260];
- CHAR SettingValue[260];
- ULONG_PTR SectionId;
+ ULONG DefaultOS = 0;
+ PCSTR DefaultOSName = NULL;
+ CHAR DefaultOSText[80];
+
+ OperatingSystemItem* Items;
+ ULONG Count;
+ ULONG i;
+ ULONG_PTR OsSectionId, SectionId;
PCHAR TitleStart, TitleEnd;
PCSTR OsLoadOptions;
- ULONG Count;
- OperatingSystemItem* Items;
+ BOOLEAN HadSection;
+ BOOLEAN HadNoBootType;
+ CHAR SettingName[260];
+ CHAR SettingValue[260];
+ CHAR BootType[80];
+ CHAR TempBuffer[sizeof(SettingValue)/sizeof(CHAR)];
- //
- // Open the [FreeLoader] section
- //
- if (!IniOpenSection("Operating Systems", &SectionId))
- {
+ /* Open the [Operating Systems] section */
+ if (!IniOpenSection("Operating Systems", &OsSectionId))
return NULL;
- }
- //
- // Count number of operating systems in the section
- //
- Count = IniGetNumSectionItems(SectionId);
+ /* Count the number of operating systems in the section */
+ Count = IniGetNumSectionItems(OsSectionId);
- //
- // Allocate memory to hold operating system lists
- //
+ /* Allocate memory to hold operating system lists */
Items = FrLdrHeapAlloc(Count * sizeof(OperatingSystemItem), TAG_OS_ITEM);
if (!Items)
- {
return NULL;
+
+ /* Retrieve which OS is the default one */
+ DefaultOSName = CmdLineGetDefaultOS();
+ if (!DefaultOSName || !*DefaultOSName)
+ {
+ if ((FrLdrSectionId != 0) &&
+ IniReadSettingByName(FrLdrSectionId, "DefaultOS", DefaultOSText, sizeof(DefaultOSText)))
+ {
+ DefaultOSName = DefaultOSText;
+ }
}
- //
- // Now loop through and read the operating system section and display names
- //
- for (Idx = 0; Idx < Count; Idx++)
+ /* Now loop through the operating system section and load each item */
+ for (i = 0; i < Count; ++i)
{
- IniReadSettingByNumber(SectionId, Idx, SettingName, sizeof(SettingName), SettingValue, sizeof(SettingValue));
+ IniReadSettingByNumber(OsSectionId, i,
+ SettingName, sizeof(SettingName),
+ SettingValue, sizeof(SettingValue));
+ if (!*SettingName)
+ {
+ ERR("Invalid OS entry %lu, skipping.\n", i);
+ continue;
+ }
- //
- // Search start and end of the title
- //
- OsLoadOptions = NULL;
+ /* Retrieve the start and end of the title */
TitleStart = SettingValue;
- while (*TitleStart == ' ' || *TitleStart == '"')
- TitleStart++;
+ /* Trim any leading whitespace and quotes */
+ while (*TitleStart == ' ' || *TitleStart == '\t' || *TitleStart == '"')
+ ++TitleStart;
TitleEnd = TitleStart;
- if (*TitleEnd != ANSI_NULL)
- TitleEnd++;
+ /* Go up to the first last quote */
while (*TitleEnd != ANSI_NULL && *TitleEnd != '"')
- TitleEnd++;
- if (*TitleEnd != ANSI_NULL)
+ ++TitleEnd;
+
+ /* NULL-terminate the title */
+ if (*TitleEnd)
+ *TitleEnd++ = ANSI_NULL; // Skip the quote too.
+
+ /* Retrieve the options after the quoted title */
+ if (*TitleEnd)
{
- *TitleEnd = ANSI_NULL;
- OsLoadOptions = TitleEnd + 1;
+ /* Trim any trailing whitespace and quotes */
+ while (*TitleEnd == ' ' || *TitleEnd == '\t' || *TitleEnd == '"')
+ ++TitleEnd;
+ }
+ OsLoadOptions = (*TitleEnd ? TitleEnd : NULL);
+
+ // TRACE("\n"
+ // "SettingName = '%s'\n"
+ // "TitleStart = '%s'\n"
+ // "OsLoadOptions = '%s'\n",
+ // SettingName, TitleStart, OsLoadOptions);
+
+ /* Find the default OS item while we haven't got one */
+ if (DefaultOSName && _stricmp(DefaultOSName, SettingName) == 0)
+ {
+ DefaultOS = i;
+ DefaultOSName = NULL; // We have found the first one, don't search for others.
+ }
+
+ /*
+ * Determine whether this is a legacy operating system entry of the form:
+ *
+ * [Operating Systems]
+ * ArcOsLoadPartition="LoadIdentifier" /List /of /Options
+ *
+ * and if so, convert it into a new operating system INI entry:
+ *
+ * [Operating Systems]
+ * SectionIdentifier="LoadIdentifier"
+ *
+ * [SectionIdentifier]
+ * BootType=...
+ * SystemPath=ArcOsLoadPartition
+ * Options=/List /of /Options
+ *
+ * The "BootType" value is heuristically determined from the form of
+ * the ArcOsLoadPartition: if this is an ARC path, the "BootType" value
+ * is "Windows", otherwise if this is a DOS path the "BootType" value
+ * is "BootSector". This ensures backwards-compatibility with NTLDR.
+ */
+
+ /* Try to open the operating system section in the .ini file */
+ SectionId = 0;
+ HadSection = IniOpenSection(SettingName, &SectionId);
+ if (HadSection)
+ {
+ /* This is a new OS entry: try to read the boot type */
+ IniReadSettingByName(SectionId, "BootType", BootType, sizeof(BootType));
+ }
+ else
+ {
+ /* This is a legacy OS entry: no explicit BootType specified, we will infer one */
+ *BootType = ANSI_NULL;
+ }
+
+ /* Check whether we have got a BootType value; if not, try to infer one */
+ HadNoBootType = (*BootType == ANSI_NULL);
+ if (HadNoBootType)
+ {
+#ifdef _M_IX86
+ ULONG FileId;
+ if (ArcOpen(SettingName, OpenReadOnly, &FileId) == ESUCCESS)
+ {
+ ArcClose(FileId);
+ strcpy(BootType, "BootSector");
+ }
+ else
+#endif
+ {
+ strcpy(BootType, "Windows");
+ }
+ }
+
+ /* This is a legacy OS entry: convert it into a new OS entry */
+ if (!HadSection)
+ {
+ TIMEINFO* TimeInfo;
+
+ /* Save the system path from the original SettingName (overwritten below) */
+ RtlStringCbCopyA(TempBuffer, sizeof(TempBuffer), SettingName);
+
+ /* Generate a unique section name */
+ TimeInfo = ArcGetTime();
+ if (_stricmp(BootType, "BootSector") == 0)
+ {
+ RtlStringCbPrintfA(SettingName, sizeof(SettingName),
+ "BootSectorFile%u%u%u%u%u%u",
+ TimeInfo->Year, TimeInfo->Day, TimeInfo->Month,
+ TimeInfo->Hour, TimeInfo->Minute, TimeInfo->Second);
+ }
+ else if (_stricmp(BootType, "Windows") == 0)
+ {
+ RtlStringCbPrintfA(SettingName, sizeof(SettingName),
+ "Windows%u%u%u%u%u%u",
+ TimeInfo->Year, TimeInfo->Day, TimeInfo->Month,
+ TimeInfo->Hour, TimeInfo->Minute, TimeInfo->Second);
+ }
+ else
+ {
+ ASSERT(FALSE);
+ }
+
+ /* Add the section */
+ if (!IniAddSection(SettingName, &SectionId))
+ {
+ ERR("Could not convert legacy OS entry %lu, skipping.\n", i);
+ continue;
+ }
+
+ /* Add the system path */
+ if (_stricmp(BootType, "BootSector") == 0)
+ {
+ if (!IniAddSettingValueToSection(SectionId, "BootSectorFile", TempBuffer))
+ {
+ ERR("Could not convert legacy OS entry %lu, skipping.\n", i);
+ continue;
+ }
+ }
+ else if (_stricmp(BootType, "Windows") == 0)
+ {
+ if (!IniAddSettingValueToSection(SectionId, "SystemPath", TempBuffer))
+ {
+ ERR("Could not convert legacy OS entry %lu, skipping.\n", i);
+ continue;
+ }
+ }
+ else
+ {
+ ASSERT(FALSE);
+ }
+
+ /* Add the OS options */
+ if (OsLoadOptions && !IniAddSettingValueToSection(SectionId, "Options", OsLoadOptions))
+ {
+ ERR("Could not convert legacy OS entry %lu, skipping.\n", i);
+ continue;
+ }
+ }
+
+ /* Add or modify the BootType if needed */
+ if (HadNoBootType && !IniModifySettingValue(SectionId, "BootType", BootType))
+ {
+ ERR("Could not fixup the BootType entry for OS '%s', ignoring.\n", SettingName);
+ }
+
+ /*
+ * If this is a new OS entry, but some options were given appended to
+ * the OS entry item, append them instead to the "Options=" value.
+ */
+ if (HadSection && OsLoadOptions && *OsLoadOptions)
+ {
+ /* Read the original "Options=" value */
+ *TempBuffer = ANSI_NULL;
+ if (!IniReadSettingByName(SectionId, "Options", TempBuffer, sizeof(TempBuffer)))
+ TRACE("No 'Options' value found for OS '%s', ignoring.\n", SettingName);
+
+ /* Concatenate the options together */
+ RtlStringCbCatA(TempBuffer, sizeof(TempBuffer), " ");
+ RtlStringCbCatA(TempBuffer, sizeof(TempBuffer), OsLoadOptions);
+
+ /* Save them */
+ if (!IniModifySettingValue(SectionId, "Options", TempBuffer))
+ ERR("Could not modify the options for OS '%s', ignoring.\n", SettingName);
}
- //
- // Copy the system partition, identifier and options
- //
- Items[Idx].SystemPartition = CopyString(SettingName);
- Items[Idx].LoadIdentifier = CopyString(TitleStart);
- Items[Idx].OsLoadOptions = CopyString(OsLoadOptions);
+ /* Copy the OS section ID and its identifier */
+ Items[i].SectionId = SectionId;
+ Items[i].LoadIdentifier = CopyString(TitleStart);
+ // TRACE("We did Items[%lu]: SectionName = '%s' (SectionId = 0x%p), LoadIdentifier = '%s'\n",
+ // i, SettingName, Items[i].SectionId, Items[i].LoadIdentifier);
}
- //
- // Return success
- //
- *OperatingSystemCountPointer = Count;
+ /* Return success */
+ *OperatingSystemCount = Count;
+ *DefaultOperatingSystem = DefaultOS;
return Items;
}