1 /* 2 * FreeLoader 3 * Copyright (C) 1998-2003 Brian Palmer <brianp@sginet.com> 4 * 5 * This program is free software; you can redistribute it and/or modify 6 * it under the terms of the GNU General Public License as published by 7 * the Free Software Foundation; either version 2 of the License, or 8 * (at your option) any later version. 9 * 10 * This program is distributed in the hope that it will be useful, 11 * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 * GNU General Public License for more details. 14 * 15 * You should have received a copy of the GNU General Public License along 16 * with this program; if not, write to the Free Software Foundation, Inc., 17 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. 18 */ 19 20 /* INCLUDES *******************************************************************/ 21 22 #include <freeldr.h> 23 24 #include <debug.h> 25 DBG_DEFAULT_CHANNEL(INIFILE); 26 27 #define TAG_OS_ITEM 'tISO' 28 29 /* FUNCTIONS ******************************************************************/ 30 31 static PCSTR CopyString(PCSTR Source) 32 { 33 PSTR Dest; 34 35 if (!Source) 36 return NULL; 37 38 Dest = FrLdrHeapAlloc(strlen(Source) + 1, TAG_STRING); 39 if (Dest) 40 strcpy(Dest, Source); 41 42 return Dest; 43 } 44 45 OperatingSystemItem* 46 InitOperatingSystemList( 47 _Out_ PULONG OperatingSystemCount, 48 _Out_ PULONG DefaultOperatingSystem) 49 { 50 OperatingSystemItem* Items; 51 PCSTR DefaultOSName; 52 ULONG DefaultOS = 0; 53 ULONG Count; 54 ULONG i; 55 ULONG_PTR OsSectionId, SectionId; 56 PCHAR TitleStart, TitleEnd; 57 PCSTR OsLoadOptions; 58 BOOLEAN HadSection; 59 BOOLEAN HadNoBootType; 60 CHAR SettingName[260]; 61 CHAR SettingValue[260]; 62 CHAR BootType[80]; 63 CHAR TempBuffer[_countof(SettingValue)]; 64 65 /* Open the [Operating Systems] section */ 66 if (!IniOpenSection("Operating Systems", &OsSectionId)) 67 return NULL; 68 69 /* Count the number of operating systems in the section */ 70 Count = IniGetNumSectionItems(OsSectionId); 71 72 /* Allocate memory to hold operating system lists */ 73 Items = FrLdrHeapAlloc(Count * sizeof(OperatingSystemItem), TAG_OS_ITEM); 74 if (!Items) 75 return NULL; 76 77 /* Retrieve the default OS */ 78 DefaultOSName = BootMgrInfo.DefaultOs; 79 80 /* Now loop through the operating system section and load each item */ 81 for (i = 0; i < Count; ++i) 82 { 83 IniReadSettingByNumber(OsSectionId, i, 84 SettingName, sizeof(SettingName), 85 SettingValue, sizeof(SettingValue)); 86 if (!*SettingName) 87 { 88 ERR("Invalid OS entry %lu, skipping.\n", i); 89 continue; 90 } 91 92 /* Retrieve the start and end of the title */ 93 TitleStart = SettingValue; 94 /* Trim any leading whitespace and quotes */ 95 while (*TitleStart == ' ' || *TitleStart == '\t' || *TitleStart == '"') 96 ++TitleStart; 97 TitleEnd = TitleStart; 98 /* Go up to the first last quote */ 99 while (*TitleEnd != ANSI_NULL && *TitleEnd != '"') 100 ++TitleEnd; 101 102 /* NULL-terminate the title */ 103 if (*TitleEnd) 104 *TitleEnd++ = ANSI_NULL; // Skip the quote too. 105 106 /* Retrieve the options after the quoted title */ 107 if (*TitleEnd) 108 { 109 /* Trim any trailing whitespace and quotes */ 110 while (*TitleEnd == ' ' || *TitleEnd == '\t' || *TitleEnd == '"') 111 ++TitleEnd; 112 } 113 OsLoadOptions = (*TitleEnd ? TitleEnd : NULL); 114 115 // TRACE("\n" 116 // "SettingName = '%s'\n" 117 // "TitleStart = '%s'\n" 118 // "OsLoadOptions = '%s'\n", 119 // SettingName, TitleStart, OsLoadOptions); 120 121 /* Find the default OS item while we haven't got one */ 122 if (DefaultOSName && _stricmp(DefaultOSName, SettingName) == 0) 123 { 124 DefaultOS = i; 125 DefaultOSName = NULL; // We have found the first one, don't search for others. 126 } 127 128 /* 129 * Determine whether this is a legacy operating system entry of the form: 130 * 131 * [Operating Systems] 132 * ArcOsLoadPartition="LoadIdentifier" /List /of /Options 133 * 134 * and if so, convert it into a new operating system INI entry: 135 * 136 * [Operating Systems] 137 * SectionIdentifier="LoadIdentifier" 138 * 139 * [SectionIdentifier] 140 * BootType=... 141 * SystemPath=ArcOsLoadPartition 142 * Options=/List /of /Options 143 * 144 * The "BootType" value is heuristically determined from the form of 145 * the ArcOsLoadPartition: if this is an ARC path, the "BootType" value 146 * is "Windows", otherwise if this is a DOS path the "BootType" value 147 * is "BootSector". This ensures backwards-compatibility with NTLDR. 148 */ 149 150 /* Try to open the operating system section in the .ini file */ 151 SectionId = 0; 152 HadSection = IniOpenSection(SettingName, &SectionId); 153 if (HadSection) 154 { 155 /* This is a new OS entry: try to read the boot type */ 156 IniReadSettingByName(SectionId, "BootType", BootType, sizeof(BootType)); 157 } 158 else 159 { 160 /* This is a legacy OS entry: no explicit BootType specified, we will infer one */ 161 *BootType = ANSI_NULL; 162 } 163 164 /* Check whether we have got a BootType value; if not, try to infer one */ 165 HadNoBootType = (*BootType == ANSI_NULL); 166 if (HadNoBootType) 167 { 168 #ifdef _M_IX86 169 ULONG FileId; 170 if (ArcOpen(SettingName, OpenReadOnly, &FileId) == ESUCCESS) 171 { 172 ArcClose(FileId); 173 strcpy(BootType, "BootSector"); 174 } 175 else 176 #endif 177 { 178 strcpy(BootType, "Windows"); 179 } 180 } 181 182 /* This is a legacy OS entry: convert it into a new OS entry */ 183 if (!HadSection) 184 { 185 TIMEINFO* TimeInfo; 186 187 /* Save the system path from the original SettingName (overwritten below) */ 188 RtlStringCbCopyA(TempBuffer, sizeof(TempBuffer), SettingName); 189 190 /* Generate a unique section name */ 191 TimeInfo = ArcGetTime(); 192 if (_stricmp(BootType, "BootSector") == 0) 193 { 194 RtlStringCbPrintfA(SettingName, sizeof(SettingName), 195 "BootSectorFile%u%u%u%u%u%u", 196 TimeInfo->Year, TimeInfo->Day, TimeInfo->Month, 197 TimeInfo->Hour, TimeInfo->Minute, TimeInfo->Second); 198 } 199 else if (_stricmp(BootType, "Windows") == 0) 200 { 201 RtlStringCbPrintfA(SettingName, sizeof(SettingName), 202 "Windows%u%u%u%u%u%u", 203 TimeInfo->Year, TimeInfo->Day, TimeInfo->Month, 204 TimeInfo->Hour, TimeInfo->Minute, TimeInfo->Second); 205 } 206 else 207 { 208 ASSERT(FALSE); 209 } 210 211 /* Add the section */ 212 if (!IniAddSection(SettingName, &SectionId)) 213 { 214 ERR("Could not convert legacy OS entry %lu, skipping.\n", i); 215 continue; 216 } 217 218 /* Add the system path */ 219 if (_stricmp(BootType, "BootSector") == 0) 220 { 221 if (!IniAddSettingValueToSection(SectionId, "BootSectorFile", TempBuffer)) 222 { 223 ERR("Could not convert legacy OS entry %lu, skipping.\n", i); 224 continue; 225 } 226 } 227 else if (_stricmp(BootType, "Windows") == 0) 228 { 229 if (!IniAddSettingValueToSection(SectionId, "SystemPath", TempBuffer)) 230 { 231 ERR("Could not convert legacy OS entry %lu, skipping.\n", i); 232 continue; 233 } 234 } 235 else 236 { 237 ASSERT(FALSE); 238 } 239 240 /* Add the OS options */ 241 if (OsLoadOptions && !IniAddSettingValueToSection(SectionId, "Options", OsLoadOptions)) 242 { 243 ERR("Could not convert legacy OS entry %lu, skipping.\n", i); 244 continue; 245 } 246 } 247 248 /* Add or modify the BootType if needed */ 249 if (HadNoBootType && !IniModifySettingValue(SectionId, "BootType", BootType)) 250 { 251 ERR("Could not fixup the BootType entry for OS '%s', ignoring.\n", SettingName); 252 } 253 254 /* 255 * If this is a new OS entry, but some options were given appended to 256 * the OS entry item, append them instead to the "Options=" value. 257 */ 258 if (HadSection && OsLoadOptions && *OsLoadOptions) 259 { 260 /* Read the original "Options=" value */ 261 *TempBuffer = ANSI_NULL; 262 if (!IniReadSettingByName(SectionId, "Options", TempBuffer, sizeof(TempBuffer))) 263 TRACE("No 'Options' value found for OS '%s', ignoring.\n", SettingName); 264 265 /* Concatenate the options together */ 266 RtlStringCbCatA(TempBuffer, sizeof(TempBuffer), " "); 267 RtlStringCbCatA(TempBuffer, sizeof(TempBuffer), OsLoadOptions); 268 269 /* Save them */ 270 if (!IniModifySettingValue(SectionId, "Options", TempBuffer)) 271 ERR("Could not modify the options for OS '%s', ignoring.\n", SettingName); 272 } 273 274 /* Copy the OS section ID and its identifier */ 275 Items[i].SectionId = SectionId; 276 Items[i].LoadIdentifier = CopyString(TitleStart); 277 // TRACE("We did Items[%lu]: SectionName = '%s' (SectionId = 0x%p), LoadIdentifier = '%s'\n", 278 // i, SettingName, Items[i].SectionId, Items[i].LoadIdentifier); 279 } 280 281 /* Return success */ 282 *OperatingSystemCount = Count; 283 *DefaultOperatingSystem = DefaultOS; 284 return Items; 285 } 286