[FREELDR] Add "Edit Boot Command Line" feature. (#1763)
[reactos.git] / boot / freeldr / freeldr / custom.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 /* GLOBALS ********************************************************************/
25
26 #ifdef _M_IX86
27
28 const CHAR BootSectorFilePrompt[] = "Enter the boot sector file path.\n\nExamples:\n\\BOOTSECT.DOS\n/boot/bootsect.dos";
29 const CHAR LinuxKernelPrompt[] = "Enter the Linux kernel image path.\n\nExamples:\n/vmlinuz\n/boot/vmlinuz-2.4.18";
30 const CHAR LinuxInitrdPrompt[] = "Enter the initrd image path.\n\nExamples:\n/initrd.gz\n/boot/root.img.gz\n\nLeave blank for no initial ram disk.";
31 const CHAR LinuxCommandLinePrompt[] = "Enter the Linux kernel command line.\n\nExamples:\nroot=/dev/hda1\nroot=/dev/fd0 read-only\nroot=/dev/sdb1 init=/sbin/init";
32
33 #endif // _M_IX86
34
35 const CHAR BootDrivePrompt[] = "Enter the boot drive.\n\nExamples:\nfd0 - first floppy drive\nhd0 - first hard drive\nhd1 - second hard drive\ncd0 - first CD-ROM drive.\n\nBIOS drive numbers may also be used:\n0 - first floppy drive\n0x80 - first hard drive\n0x81 - second hard drive";
36 const CHAR BootPartitionPrompt[] = "Enter the boot partition.\n\nEnter 0 for the active (bootable) partition.";
37 const CHAR ReactOSSystemPathPrompt[] = "Enter the path to your ReactOS system directory.\n\nExamples:\n\\REACTOS\n\\ROS";
38 const CHAR ReactOSOptionsPrompt[] = "Enter the options you want passed to the kernel.\n\nExamples:\n/DEBUG /DEBUGPORT=COM1 /BAUDRATE=115200\n/FASTDETECT /SOS /NOGUIBOOT\n/BASEVIDEO /MAXMEM=64\n/KERNEL=NTKRNLMP.EXE /HAL=HALMPS.DLL";
39 const CHAR CustomBootPrompt[] = "Press ENTER to boot your custom boot setup.";
40
41 /* FUNCTIONS ******************************************************************/
42
43 #ifdef HAS_OPTION_MENU_CUSTOM_BOOT
44
45 VOID OptionMenuCustomBoot(VOID)
46 {
47 PCSTR CustomBootMenuList[] = {
48 #ifdef _M_IX86
49 "Disk",
50 "Partition",
51 "Boot Sector File",
52 "Linux",
53 #endif
54 "ReactOS"
55 };
56 ULONG SelectedMenuItem;
57
58 if (!UiDisplayMenu("Please choose a boot method:", NULL,
59 FALSE,
60 CustomBootMenuList,
61 sizeof(CustomBootMenuList) / sizeof(CustomBootMenuList[0]),
62 0, -1,
63 &SelectedMenuItem,
64 TRUE,
65 NULL, NULL))
66 {
67 /* The user pressed ESC */
68 return;
69 }
70
71 switch (SelectedMenuItem)
72 {
73 #ifdef _M_IX86
74 case 0: // Disk
75 EditCustomBootDisk(0);
76 break;
77 case 1: // Partition
78 EditCustomBootPartition(0);
79 break;
80 case 2: // Boot Sector File
81 EditCustomBootSectorFile(0);
82 break;
83 case 3: // Linux
84 EditCustomBootLinux(0);
85 break;
86 case 4: // ReactOS
87 #else
88 case 0:
89 #endif
90 EditCustomBootReactOS(0);
91 break;
92 }
93 }
94
95 #endif // HAS_OPTION_MENU_CUSTOM_BOOT
96
97 #ifdef _M_IX86
98
99 VOID EditCustomBootDisk(IN ULONG_PTR SectionId OPTIONAL)
100 {
101 TIMEINFO* TimeInfo;
102 OperatingSystemItem OperatingSystem;
103 CHAR SectionName[100];
104 CHAR BootDriveString[20];
105
106 RtlZeroMemory(SectionName, sizeof(SectionName));
107 RtlZeroMemory(BootDriveString, sizeof(BootDriveString));
108
109 if (SectionId != 0)
110 {
111 /* Load the settings */
112 IniReadSettingByName(SectionId, "BootDrive", BootDriveString, sizeof(BootDriveString));
113 }
114
115 if (!UiEditBox(BootDrivePrompt, BootDriveString, sizeof(BootDriveString)))
116 return;
117
118 /* Modify the settings values and return if we were in edit mode */
119 if (SectionId != 0)
120 {
121 IniModifySettingValue(SectionId, "BootDrive", BootDriveString);
122 return;
123 }
124
125 /* Generate a unique section name */
126 TimeInfo = ArcGetTime();
127 RtlStringCbPrintfA(SectionName, sizeof(SectionName),
128 "CustomBootDisk%u%u%u%u%u%u",
129 TimeInfo->Year, TimeInfo->Day, TimeInfo->Month,
130 TimeInfo->Hour, TimeInfo->Minute, TimeInfo->Second);
131
132 /* Add the section */
133 if (!IniAddSection(SectionName, &SectionId))
134 return;
135
136 /* Add the BootType */
137 if (!IniAddSettingValueToSection(SectionId, "BootType", "Drive"))
138 return;
139
140 /* Add the BootDrive */
141 if (!IniAddSettingValueToSection(SectionId, "BootDrive", BootDriveString))
142 return;
143
144 UiMessageBox(CustomBootPrompt);
145
146 OperatingSystem.SectionName = SectionName;
147 OperatingSystem.LoadIdentifier = NULL;
148 LoadOperatingSystem(&OperatingSystem);
149 }
150
151 VOID EditCustomBootPartition(IN ULONG_PTR SectionId OPTIONAL)
152 {
153 TIMEINFO* TimeInfo;
154 OperatingSystemItem OperatingSystem;
155 CHAR SectionName[100];
156 CHAR BootDriveString[20];
157 CHAR BootPartitionString[20];
158
159 RtlZeroMemory(SectionName, sizeof(SectionName));
160 RtlZeroMemory(BootDriveString, sizeof(BootDriveString));
161 RtlZeroMemory(BootPartitionString, sizeof(BootPartitionString));
162
163 if (SectionId != 0)
164 {
165 /* Load the settings */
166 IniReadSettingByName(SectionId, "BootDrive", BootDriveString, sizeof(BootDriveString));
167 IniReadSettingByName(SectionId, "BootPartition", BootPartitionString, sizeof(BootPartitionString));
168 }
169
170 if (!UiEditBox(BootDrivePrompt, BootDriveString, sizeof(BootDriveString)))
171 return;
172
173 if (!UiEditBox(BootPartitionPrompt, BootPartitionString, sizeof(BootPartitionString)))
174 return;
175
176 /* Modify the settings values and return if we were in edit mode */
177 if (SectionId != 0)
178 {
179 IniModifySettingValue(SectionId, "BootDrive", BootDriveString);
180 IniModifySettingValue(SectionId, "BootPartition", BootPartitionString);
181 return;
182 }
183
184 /* Generate a unique section name */
185 TimeInfo = ArcGetTime();
186 RtlStringCbPrintfA(SectionName, sizeof(SectionName),
187 "CustomBootPartition%u%u%u%u%u%u",
188 TimeInfo->Year, TimeInfo->Day, TimeInfo->Month,
189 TimeInfo->Hour, TimeInfo->Minute, TimeInfo->Second);
190
191 /* Add the section */
192 if (!IniAddSection(SectionName, &SectionId))
193 return;
194
195 /* Add the BootType */
196 if (!IniAddSettingValueToSection(SectionId, "BootType", "Partition"))
197 return;
198
199 /* Add the BootDrive */
200 if (!IniAddSettingValueToSection(SectionId, "BootDrive", BootDriveString))
201 return;
202
203 /* Add the BootPartition */
204 if (!IniAddSettingValueToSection(SectionId, "BootPartition", BootPartitionString))
205 return;
206
207 UiMessageBox(CustomBootPrompt);
208
209 OperatingSystem.SectionName = SectionName;
210 OperatingSystem.LoadIdentifier = NULL;
211 LoadOperatingSystem(&OperatingSystem);
212 }
213
214 VOID EditCustomBootSectorFile(IN ULONG_PTR SectionId OPTIONAL)
215 {
216 TIMEINFO* TimeInfo;
217 OperatingSystemItem OperatingSystem;
218 CHAR SectionName[100];
219 CHAR BootDriveString[20];
220 CHAR BootPartitionString[20];
221 CHAR BootSectorFileString[200];
222
223 RtlZeroMemory(SectionName, sizeof(SectionName));
224 RtlZeroMemory(BootDriveString, sizeof(BootDriveString));
225 RtlZeroMemory(BootPartitionString, sizeof(BootPartitionString));
226 RtlZeroMemory(BootSectorFileString, sizeof(BootSectorFileString));
227
228 if (SectionId != 0)
229 {
230 /* Load the settings */
231 IniReadSettingByName(SectionId, "BootDrive", BootDriveString, sizeof(BootDriveString));
232 IniReadSettingByName(SectionId, "BootPartition", BootPartitionString, sizeof(BootPartitionString));
233 IniReadSettingByName(SectionId, "BootSectorFile", BootSectorFileString, sizeof(BootSectorFileString));
234 }
235
236 if (!UiEditBox(BootDrivePrompt, BootDriveString, sizeof(BootDriveString)))
237 return;
238
239 if (!UiEditBox(BootPartitionPrompt, BootPartitionString, sizeof(BootPartitionString)))
240 return;
241
242 if (!UiEditBox(BootSectorFilePrompt, BootSectorFileString, sizeof(BootSectorFileString)))
243 return;
244
245 /* Modify the settings values and return if we were in edit mode */
246 if (SectionId != 0)
247 {
248 IniModifySettingValue(SectionId, "BootDrive", BootDriveString);
249 IniModifySettingValue(SectionId, "BootPartition", BootPartitionString);
250 IniModifySettingValue(SectionId, "BootSectorFile", BootSectorFileString);
251 return;
252 }
253
254 /* Generate a unique section name */
255 TimeInfo = ArcGetTime();
256 RtlStringCbPrintfA(SectionName, sizeof(SectionName),
257 "CustomBootSectorFile%u%u%u%u%u%u",
258 TimeInfo->Year, TimeInfo->Day, TimeInfo->Month,
259 TimeInfo->Hour, TimeInfo->Minute, TimeInfo->Second);
260
261 /* Add the section */
262 if (!IniAddSection(SectionName, &SectionId))
263 return;
264
265 /* Add the BootType */
266 if (!IniAddSettingValueToSection(SectionId, "BootType", "BootSector"))
267 return;
268
269 /* Add the BootDrive */
270 if (!IniAddSettingValueToSection(SectionId, "BootDrive", BootDriveString))
271 return;
272
273 /* Add the BootPartition */
274 if (!IniAddSettingValueToSection(SectionId, "BootPartition", BootPartitionString))
275 return;
276
277 /* Add the BootSectorFile */
278 if (!IniAddSettingValueToSection(SectionId, "BootSectorFile", BootSectorFileString))
279 return;
280
281 UiMessageBox(CustomBootPrompt);
282
283 OperatingSystem.SectionName = SectionName;
284 OperatingSystem.LoadIdentifier = NULL;
285 LoadOperatingSystem(&OperatingSystem);
286 }
287
288 VOID EditCustomBootLinux(IN ULONG_PTR SectionId OPTIONAL)
289 {
290 TIMEINFO* TimeInfo;
291 OperatingSystemItem OperatingSystem;
292 CHAR SectionName[100];
293 CHAR BootDriveString[20];
294 CHAR BootPartitionString[20];
295 CHAR LinuxKernelString[200];
296 CHAR LinuxInitrdString[200];
297 CHAR LinuxCommandLineString[200];
298
299 RtlZeroMemory(SectionName, sizeof(SectionName));
300 RtlZeroMemory(BootDriveString, sizeof(BootDriveString));
301 RtlZeroMemory(BootPartitionString, sizeof(BootPartitionString));
302 RtlZeroMemory(LinuxKernelString, sizeof(LinuxKernelString));
303 RtlZeroMemory(LinuxInitrdString, sizeof(LinuxInitrdString));
304 RtlZeroMemory(LinuxCommandLineString, sizeof(LinuxCommandLineString));
305
306 if (SectionId != 0)
307 {
308 /* Load the settings */
309 IniReadSettingByName(SectionId, "BootDrive", BootDriveString, sizeof(BootDriveString));
310 IniReadSettingByName(SectionId, "BootPartition", BootPartitionString, sizeof(BootPartitionString));
311 IniReadSettingByName(SectionId, "Kernel", LinuxKernelString, sizeof(LinuxKernelString));
312 IniReadSettingByName(SectionId, "Initrd", LinuxInitrdString, sizeof(LinuxInitrdString));
313 IniReadSettingByName(SectionId, "CommandLine", LinuxCommandLineString, sizeof(LinuxCommandLineString));
314 }
315
316 if (!UiEditBox(BootDrivePrompt, BootDriveString, sizeof(BootDriveString)))
317 return;
318
319 if (!UiEditBox(BootPartitionPrompt, BootPartitionString, sizeof(BootPartitionString)))
320 return;
321
322 if (!UiEditBox(LinuxKernelPrompt, LinuxKernelString, sizeof(LinuxKernelString)))
323 return;
324
325 if (!UiEditBox(LinuxInitrdPrompt, LinuxInitrdString, sizeof(LinuxInitrdString)))
326 return;
327
328 if (!UiEditBox(LinuxCommandLinePrompt, LinuxCommandLineString, sizeof(LinuxCommandLineString)))
329 return;
330
331 /* Modify the settings values and return if we were in edit mode */
332 if (SectionId != 0)
333 {
334 IniModifySettingValue(SectionId, "BootDrive", BootDriveString);
335 IniModifySettingValue(SectionId, "BootPartition", BootPartitionString);
336 IniModifySettingValue(SectionId, "Kernel", LinuxKernelString);
337 IniModifySettingValue(SectionId, "Initrd", LinuxInitrdString);
338 IniModifySettingValue(SectionId, "CommandLine", LinuxCommandLineString);
339 return;
340 }
341
342 /* Generate a unique section name */
343 TimeInfo = ArcGetTime();
344 RtlStringCbPrintfA(SectionName, sizeof(SectionName),
345 "CustomLinux%u%u%u%u%u%u",
346 TimeInfo->Year, TimeInfo->Day, TimeInfo->Month,
347 TimeInfo->Hour, TimeInfo->Minute, TimeInfo->Second);
348
349 /* Add the section */
350 if (!IniAddSection(SectionName, &SectionId))
351 return;
352
353 /* Add the BootType */
354 if (!IniAddSettingValueToSection(SectionId, "BootType", "Linux"))
355 return;
356
357 /* Add the BootDrive */
358 if (!IniAddSettingValueToSection(SectionId, "BootDrive", BootDriveString))
359 return;
360
361 /* Add the BootPartition */
362 if (!IniAddSettingValueToSection(SectionId, "BootPartition", BootPartitionString))
363 return;
364
365 /* Add the Kernel */
366 if (!IniAddSettingValueToSection(SectionId, "Kernel", LinuxKernelString))
367 return;
368
369 /* Add the Initrd */
370 if (*LinuxInitrdString)
371 {
372 if (!IniAddSettingValueToSection(SectionId, "Initrd", LinuxInitrdString))
373 return;
374 }
375
376 /* Add the CommandLine */
377 if (!IniAddSettingValueToSection(SectionId, "CommandLine", LinuxCommandLineString))
378 return;
379
380 UiMessageBox(CustomBootPrompt);
381
382 OperatingSystem.SectionName = SectionName;
383 OperatingSystem.LoadIdentifier = "Custom Linux Setup";
384 LoadOperatingSystem(&OperatingSystem);
385 }
386
387 #endif // _M_IX86
388
389 VOID EditCustomBootReactOS(IN ULONG_PTR SectionId OPTIONAL)
390 {
391 TIMEINFO* TimeInfo;
392 OperatingSystemItem OperatingSystem;
393 CHAR SectionName[100];
394 CHAR BootDriveString[20];
395 CHAR BootPartitionString[20];
396 CHAR ReactOSSystemPath[200];
397 CHAR ReactOSARCPath[200];
398 CHAR ReactOSOptions[200];
399
400 RtlZeroMemory(SectionName, sizeof(SectionName));
401 RtlZeroMemory(BootDriveString, sizeof(BootDriveString));
402 RtlZeroMemory(BootPartitionString, sizeof(BootPartitionString));
403 RtlZeroMemory(ReactOSSystemPath, sizeof(ReactOSSystemPath));
404 RtlZeroMemory(ReactOSARCPath, sizeof(ReactOSARCPath));
405 RtlZeroMemory(ReactOSOptions, sizeof(ReactOSOptions));
406
407 if (SectionId != 0)
408 {
409 /* Load the settings */
410 // TODO? Maybe use DissectArcPath(CHAR *ArcPath, CHAR *BootPath, UCHAR* BootDrive, ULONG* BootPartition) to get back to the small elements.
411 IniReadSettingByName(SectionId, "SystemPath", ReactOSARCPath, sizeof(ReactOSARCPath));
412 IniReadSettingByName(SectionId, "Options", ReactOSOptions, sizeof(ReactOSOptions));
413 }
414
415 if (SectionId == 0)
416 {
417 if (!UiEditBox(BootDrivePrompt, BootDriveString, sizeof(BootDriveString)))
418 return;
419
420 if (!UiEditBox(BootPartitionPrompt, BootPartitionString, sizeof(BootPartitionString)))
421 return;
422
423 if (!UiEditBox(ReactOSSystemPathPrompt, ReactOSSystemPath, sizeof(ReactOSSystemPath)))
424 return;
425 }
426 else
427 {
428 if (!UiEditBox(ReactOSSystemPathPrompt, ReactOSARCPath, sizeof(ReactOSARCPath)))
429 return;
430 }
431
432 if (!UiEditBox(ReactOSOptionsPrompt, ReactOSOptions, sizeof(ReactOSOptions)))
433 return;
434
435 /* Modify the settings values and return if we were in edit mode */
436 if (SectionId != 0)
437 {
438 IniModifySettingValue(SectionId, "SystemPath", ReactOSARCPath);
439 IniModifySettingValue(SectionId, "Options", ReactOSOptions);
440 return;
441 }
442
443 /* Generate a unique section name */
444 TimeInfo = ArcGetTime();
445 RtlStringCbPrintfA(SectionName, sizeof(SectionName),
446 "CustomReactOS%u%u%u%u%u%u",
447 TimeInfo->Year, TimeInfo->Day, TimeInfo->Month,
448 TimeInfo->Hour, TimeInfo->Minute, TimeInfo->Second);
449
450 /* Add the section */
451 if (!IniAddSection(SectionName, &SectionId))
452 return;
453
454 /* Add the BootType */
455 if (!IniAddSettingValueToSection(SectionId, "BootType", "Windows2003"))
456 return;
457
458 /* Construct the ReactOS ARC system path */
459 ConstructArcPath(ReactOSARCPath, ReactOSSystemPath, DriveMapGetBiosDriveNumber(BootDriveString), atoi(BootPartitionString));
460
461 /* Add the system path */
462 if (!IniAddSettingValueToSection(SectionId, "SystemPath", ReactOSARCPath))
463 return;
464
465 /* Add the CommandLine */
466 if (!IniAddSettingValueToSection(SectionId, "Options", ReactOSOptions))
467 return;
468
469 UiMessageBox(CustomBootPrompt);
470
471 OperatingSystem.SectionName = SectionName;
472 OperatingSystem.LoadIdentifier = NULL;
473 LoadOperatingSystem(&OperatingSystem);
474 }
475
476 #ifdef HAS_OPTION_MENU_REBOOT
477
478 VOID OptionMenuReboot(VOID)
479 {
480 UiMessageBox("The system will now reboot.");
481
482 #if defined(__i386__) || defined(_M_AMD64)
483 DiskStopFloppyMotor();
484 #endif
485 Reboot();
486 }
487
488 #endif // HAS_OPTION_MENU_REBOOT