[FREELDR] Advance the file pointers every time a read operation is performed, in...
[reactos.git] / boot / freeldr / freeldr / oslist.c
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 IN ULONG_PTR FrLdrSectionId,
48 OUT PULONG OperatingSystemCount,
49 OUT PULONG DefaultOperatingSystem)
50 {
51 ULONG DefaultOS = 0;
52 PCSTR DefaultOSName = NULL;
53 CHAR DefaultOSText[80];
54
55 OperatingSystemItem* Items;
56 ULONG Count;
57 ULONG i;
58 ULONG_PTR OsSectionId, SectionId;
59 PCHAR TitleStart, TitleEnd;
60 PCSTR OsLoadOptions;
61 BOOLEAN HadSection;
62 BOOLEAN HadNoBootType;
63 CHAR SettingName[260];
64 CHAR SettingValue[260];
65 CHAR BootType[80];
66 CHAR TempBuffer[sizeof(SettingValue)/sizeof(CHAR)];
67
68 /* Open the [Operating Systems] section */
69 if (!IniOpenSection("Operating Systems", &OsSectionId))
70 return NULL;
71
72 /* Count the number of operating systems in the section */
73 Count = IniGetNumSectionItems(OsSectionId);
74
75 /* Allocate memory to hold operating system lists */
76 Items = FrLdrHeapAlloc(Count * sizeof(OperatingSystemItem), TAG_OS_ITEM);
77 if (!Items)
78 return NULL;
79
80 /* Retrieve which OS is the default one */
81 DefaultOSName = CmdLineGetDefaultOS();
82 if (!DefaultOSName || !*DefaultOSName)
83 {
84 if ((FrLdrSectionId != 0) &&
85 IniReadSettingByName(FrLdrSectionId, "DefaultOS", DefaultOSText, sizeof(DefaultOSText)))
86 {
87 DefaultOSName = DefaultOSText;
88 }
89 }
90
91 /* Now loop through the operating system section and load each item */
92 for (i = 0; i < Count; ++i)
93 {
94 IniReadSettingByNumber(OsSectionId, i,
95 SettingName, sizeof(SettingName),
96 SettingValue, sizeof(SettingValue));
97 if (!*SettingName)
98 {
99 ERR("Invalid OS entry %lu, skipping.\n", i);
100 continue;
101 }
102
103 /* Retrieve the start and end of the title */
104 TitleStart = SettingValue;
105 /* Trim any leading whitespace and quotes */
106 while (*TitleStart == ' ' || *TitleStart == '\t' || *TitleStart == '"')
107 ++TitleStart;
108 TitleEnd = TitleStart;
109 /* Go up to the first last quote */
110 while (*TitleEnd != ANSI_NULL && *TitleEnd != '"')
111 ++TitleEnd;
112
113 /* NULL-terminate the title */
114 if (*TitleEnd)
115 *TitleEnd++ = ANSI_NULL; // Skip the quote too.
116
117 /* Retrieve the options after the quoted title */
118 if (*TitleEnd)
119 {
120 /* Trim any trailing whitespace and quotes */
121 while (*TitleEnd == ' ' || *TitleEnd == '\t' || *TitleEnd == '"')
122 ++TitleEnd;
123 }
124 OsLoadOptions = (*TitleEnd ? TitleEnd : NULL);
125
126 // TRACE("\n"
127 // "SettingName = '%s'\n"
128 // "TitleStart = '%s'\n"
129 // "OsLoadOptions = '%s'\n",
130 // SettingName, TitleStart, OsLoadOptions);
131
132 /* Find the default OS item while we haven't got one */
133 if (DefaultOSName && _stricmp(DefaultOSName, SettingName) == 0)
134 {
135 DefaultOS = i;
136 DefaultOSName = NULL; // We have found the first one, don't search for others.
137 }
138
139 /*
140 * Determine whether this is a legacy operating system entry of the form:
141 *
142 * [Operating Systems]
143 * ArcOsLoadPartition="LoadIdentifier" /List /of /Options
144 *
145 * and if so, convert it into a new operating system INI entry:
146 *
147 * [Operating Systems]
148 * SectionIdentifier="LoadIdentifier"
149 *
150 * [SectionIdentifier]
151 * BootType=...
152 * SystemPath=ArcOsLoadPartition
153 * Options=/List /of /Options
154 *
155 * The "BootType" value is heuristically determined from the form of
156 * the ArcOsLoadPartition: if this is an ARC path, the "BootType" value
157 * is "Windows", otherwise if this is a DOS path the "BootType" value
158 * is "BootSector". This ensures backwards-compatibility with NTLDR.
159 */
160
161 /* Try to open the operating system section in the .ini file */
162 SectionId = 0;
163 HadSection = IniOpenSection(SettingName, &SectionId);
164 if (HadSection)
165 {
166 /* This is a new OS entry: try to read the boot type */
167 IniReadSettingByName(SectionId, "BootType", BootType, sizeof(BootType));
168 }
169 else
170 {
171 /* This is a legacy OS entry: no explicit BootType specified, we will infer one */
172 *BootType = ANSI_NULL;
173 }
174
175 /* Check whether we have got a BootType value; if not, try to infer one */
176 HadNoBootType = (*BootType == ANSI_NULL);
177 if (HadNoBootType)
178 {
179 #ifdef _M_IX86
180 ULONG FileId;
181 if (ArcOpen(SettingName, OpenReadOnly, &FileId) == ESUCCESS)
182 {
183 ArcClose(FileId);
184 strcpy(BootType, "BootSector");
185 }
186 else
187 #endif
188 {
189 strcpy(BootType, "Windows");
190 }
191 }
192
193 /* This is a legacy OS entry: convert it into a new OS entry */
194 if (!HadSection)
195 {
196 TIMEINFO* TimeInfo;
197
198 /* Save the system path from the original SettingName (overwritten below) */
199 RtlStringCbCopyA(TempBuffer, sizeof(TempBuffer), SettingName);
200
201 /* Generate a unique section name */
202 TimeInfo = ArcGetTime();
203 if (_stricmp(BootType, "BootSector") == 0)
204 {
205 RtlStringCbPrintfA(SettingName, sizeof(SettingName),
206 "BootSectorFile%u%u%u%u%u%u",
207 TimeInfo->Year, TimeInfo->Day, TimeInfo->Month,
208 TimeInfo->Hour, TimeInfo->Minute, TimeInfo->Second);
209 }
210 else if (_stricmp(BootType, "Windows") == 0)
211 {
212 RtlStringCbPrintfA(SettingName, sizeof(SettingName),
213 "Windows%u%u%u%u%u%u",
214 TimeInfo->Year, TimeInfo->Day, TimeInfo->Month,
215 TimeInfo->Hour, TimeInfo->Minute, TimeInfo->Second);
216 }
217 else
218 {
219 ASSERT(FALSE);
220 }
221
222 /* Add the section */
223 if (!IniAddSection(SettingName, &SectionId))
224 {
225 ERR("Could not convert legacy OS entry %lu, skipping.\n", i);
226 continue;
227 }
228
229 /* Add the system path */
230 if (_stricmp(BootType, "BootSector") == 0)
231 {
232 if (!IniAddSettingValueToSection(SectionId, "BootSectorFile", TempBuffer))
233 {
234 ERR("Could not convert legacy OS entry %lu, skipping.\n", i);
235 continue;
236 }
237 }
238 else if (_stricmp(BootType, "Windows") == 0)
239 {
240 if (!IniAddSettingValueToSection(SectionId, "SystemPath", TempBuffer))
241 {
242 ERR("Could not convert legacy OS entry %lu, skipping.\n", i);
243 continue;
244 }
245 }
246 else
247 {
248 ASSERT(FALSE);
249 }
250
251 /* Add the OS options */
252 if (OsLoadOptions && !IniAddSettingValueToSection(SectionId, "Options", OsLoadOptions))
253 {
254 ERR("Could not convert legacy OS entry %lu, skipping.\n", i);
255 continue;
256 }
257 }
258
259 /* Add or modify the BootType if needed */
260 if (HadNoBootType && !IniModifySettingValue(SectionId, "BootType", BootType))
261 {
262 ERR("Could not fixup the BootType entry for OS '%s', ignoring.\n", SettingName);
263 }
264
265 /*
266 * If this is a new OS entry, but some options were given appended to
267 * the OS entry item, append them instead to the "Options=" value.
268 */
269 if (HadSection && OsLoadOptions && *OsLoadOptions)
270 {
271 /* Read the original "Options=" value */
272 *TempBuffer = ANSI_NULL;
273 if (!IniReadSettingByName(SectionId, "Options", TempBuffer, sizeof(TempBuffer)))
274 TRACE("No 'Options' value found for OS '%s', ignoring.\n", SettingName);
275
276 /* Concatenate the options together */
277 RtlStringCbCatA(TempBuffer, sizeof(TempBuffer), " ");
278 RtlStringCbCatA(TempBuffer, sizeof(TempBuffer), OsLoadOptions);
279
280 /* Save them */
281 if (!IniModifySettingValue(SectionId, "Options", TempBuffer))
282 ERR("Could not modify the options for OS '%s', ignoring.\n", SettingName);
283 }
284
285 /* Copy the OS section ID and its identifier */
286 Items[i].SectionId = SectionId;
287 Items[i].LoadIdentifier = CopyString(TitleStart);
288 // TRACE("We did Items[%lu]: SectionName = '%s' (SectionId = 0x%p), LoadIdentifier = '%s'\n",
289 // i, SettingName, Items[i].SectionId, Items[i].LoadIdentifier);
290 }
291
292 /* Return success */
293 *OperatingSystemCount = Count;
294 *DefaultOperatingSystem = DefaultOS;
295 return Items;
296 }