xref: /reactos/boot/freeldr/freeldr/oslist.c (revision cadfdc55)
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