vfs: check userland buffers before reading them.
[haiku.git] / src / apps / bootmanager / BootManagerController.cpp
blobab1c92acae274841f88d56fb9021326194d6b269
1 /*
2 * Copyright 2008-2011, Haiku, Inc. All rights reserved.
3 * Distributed under the terms of the MIT License.
5 * Authors:
6 * Axel Dörfler, axeld@pinc-software.de
7 * Michael Pfeiffer <laplace@users.sourceforge.net>
8 */
11 #include "BootManagerController.h"
13 #include <Alert.h>
14 #include <Application.h>
15 #include <Catalog.h>
16 #include <File.h>
17 #include <FindDirectory.h>
18 #include <Locale.h>
19 #include <Path.h>
20 #include <String.h>
22 #include "BootDrive.h"
23 #include "DefaultPartitionPage.h"
24 #include "DescriptionPage.h"
25 #include "DrivesPage.h"
26 #include "FileSelectionPage.h"
27 #include "LegacyBootMenu.h"
28 #include "PartitionsPage.h"
29 #include "WizardView.h"
32 #undef B_TRANSLATION_CONTEXT
33 #define B_TRANSLATION_CONTEXT "BootManagerController"
36 BootManagerController::BootManagerController()
38 fBootDrive(NULL),
39 fBootMenu(NULL)
41 // set defaults
42 fSettings.AddBool("install", true);
43 fSettings.AddInt32("defaultPartition", 0);
44 fSettings.AddInt32("timeout", -1);
46 BPath path;
47 if (find_directory(B_USER_SETTINGS_DIRECTORY, &path, true) == B_OK) {
48 path.Append("bootman/MBR");
49 fSettings.AddString("file", path.Path());
50 // create directory
51 BPath parent;
52 if (path.GetParent(&parent) == B_OK) {
53 BDirectory directory;
54 directory.CreateDirectory(parent.Path(), NULL);
56 } else {
57 fSettings.AddString("file", "");
60 // That's the only boot menu we support at the moment.
61 fBootMenus.AddItem(new LegacyBootMenu());
65 BootManagerController::~BootManagerController()
70 void
71 BootManagerController::Previous(WizardView* wizard)
73 if (CurrentState() != kStateEntry)
74 WizardController::Previous(wizard);
75 else {
76 fSettings.ReplaceBool("install", false);
77 WizardController::Next(wizard);
82 int32
83 BootManagerController::InitialState()
85 return kStateEntry;
89 int32
90 BootManagerController::NextState(int32 state)
92 switch (state) {
93 case kStateEntry:
95 const char* path;
96 if (fSettings.FindString("disk", &path) != B_OK)
97 return kStateErrorEntry;
99 delete fBootDrive;
101 fBootDrive = new BootDrive(path);
102 fBootMenu = fBootDrive->InstalledMenu(fBootMenus);
104 if (fSettings.FindBool("install")) {
105 int32 nextState = fBootMenu != NULL
106 ? kStatePartitions : kStateSaveMBR;
108 // TODO: call BootDrive::AddSupportedMenus() once we support
109 // more than one type of boot menu - we'll probably need a
110 // requester to choose from them then as well.
111 if (fBootMenu == NULL)
112 fBootMenu = fBootMenus.ItemAt(0);
114 fCollectPartitionsStatus = fBootMenu->CollectPartitions(
115 *fBootDrive, fSettings);
117 return nextState;
120 return kStateUninstall;
123 case kStateErrorEntry:
124 be_app->PostMessage(B_QUIT_REQUESTED);
125 break;
127 case kStateSaveMBR:
128 if (_SaveMBR())
129 return kStateMBRSaved;
130 break;
132 case kStateMBRSaved:
133 return kStatePartitions;
135 case kStatePartitions:
136 if (_HasSelectedPartitions())
137 return kStateDefaultPartitions;
138 break;
140 case kStateDefaultPartitions:
141 return kStateInstallSummary;
143 case kStateInstallSummary:
144 if (_WriteBootMenu())
145 return kStateInstalled;
146 break;
148 case kStateInstalled:
149 be_app->PostMessage(B_QUIT_REQUESTED);
150 break;
152 case kStateUninstall:
153 if (_RestoreMBR())
154 return kStateUninstalled;
155 break;
157 case kStateUninstalled:
158 be_app->PostMessage(B_QUIT_REQUESTED);
159 break;
161 // cannot leave the current state/page
162 return -1;
166 bool
167 BootManagerController::_HasSelectedPartitions()
169 BMessage message;
170 for (int32 i = 0; fSettings.FindMessage("partition", i, &message) == B_OK;
171 i++) {
172 bool show;
173 if (message.FindBool("show", &show) == B_OK && show)
174 return true;
177 BAlert* alert = new BAlert("info",
178 B_TRANSLATE("At least one partition must be selected!"),
179 B_TRANSLATE_COMMENT("OK", "Button"));
180 alert->SetFlags(alert->Flags() | B_CLOSE_ON_ESCAPE);
181 alert->Go();
183 return false;
187 bool
188 BootManagerController::_WriteBootMenu()
190 BAlert* alert = new BAlert("confirm", B_TRANSLATE("About to write the "
191 "boot menu to disk. Are you sure you want to continue?"),
192 B_TRANSLATE_COMMENT("Write boot menu", "Button"),
193 B_TRANSLATE_COMMENT("Back", "Button"), NULL, B_WIDTH_AS_USUAL,
194 B_WARNING_ALERT);
196 if (alert->Go() == 1)
197 return false;
199 fWriteBootMenuStatus = fBootMenu->Install(*fBootDrive, fSettings);
200 return true;
204 bool
205 BootManagerController::_SaveMBR()
207 BString path;
208 fSettings.FindString("file", &path);
209 BFile file(path.String(), B_READ_WRITE | B_CREATE_FILE | B_ERASE_FILE);
210 fSaveMBRStatus = fBootMenu->SaveMasterBootRecord(&fSettings, &file);
211 return true;
215 bool
216 BootManagerController::_RestoreMBR()
218 BString disk;
219 BString path;
220 fSettings.FindString("disk", &disk);
221 fSettings.FindString("file", &path);
223 BString message;
224 message << B_TRANSLATE_COMMENT("About to restore the Master Boot Record "
225 "(MBR) of %disk from %file. Do you wish to continue?",
226 "Don't translate the place holders: %disk and %file");
227 message.ReplaceFirst("%disk", disk);
228 message.ReplaceFirst("%file", path);
230 BAlert* alert = new BAlert("confirm", message.String(),
231 B_TRANSLATE_COMMENT("Restore MBR", "Button"),
232 B_TRANSLATE_COMMENT("Back", "Button"),
233 NULL, B_WIDTH_AS_USUAL, B_WARNING_ALERT);
234 if (alert->Go() == 1)
235 return false;
237 BFile file(path.String(), B_READ_ONLY);
238 fRestoreMBRStatus = fBootMenu->RestoreMasterBootRecord(&fSettings, &file);
239 return true;
243 WizardPageView*
244 BootManagerController::CreatePage(int32 state, WizardView* wizard)
246 WizardPageView* page = NULL;
247 BRect frame(0, 0, 300, 250);
249 switch (state) {
250 case kStateEntry:
251 fSettings.ReplaceBool("install", true);
252 page = new DrivesPage(wizard, fBootMenus, &fSettings, "drives");
253 break;
254 case kStateErrorEntry:
255 page = _CreateErrorEntryPage();
256 wizard->SetPreviousButtonHidden(true);
257 wizard->SetNextButtonLabel(B_TRANSLATE_COMMENT("Done", "Button"));
258 break;
259 case kStateSaveMBR:
260 page = _CreateSaveMBRPage(frame);
261 wizard->SetPreviousButtonHidden(false);
262 break;
263 case kStateMBRSaved:
264 page = _CreateMBRSavedPage();
265 break;
266 case kStatePartitions:
267 page = new PartitionsPage(&fSettings, "partitions");
268 wizard->SetPreviousButtonHidden(false);
269 break;
270 case kStateDefaultPartitions:
271 page = new DefaultPartitionPage(&fSettings, frame, "default");
272 break;
273 case kStateInstallSummary:
274 page = _CreateInstallSummaryPage();
275 break;
276 case kStateInstalled:
277 page = _CreateInstalledPage();
278 wizard->SetNextButtonLabel(B_TRANSLATE_COMMENT("Done", "Button"));
279 break;
280 case kStateUninstall:
281 page = _CreateUninstallPage(frame);
282 wizard->SetPreviousButtonHidden(false);
283 break;
284 case kStateUninstalled:
285 // TODO prevent overwriting MBR after clicking "Previous"
286 page = _CreateUninstalledPage();
287 wizard->SetNextButtonLabel(B_TRANSLATE_COMMENT("Done", "Button"));
288 break;
291 return page;
295 WizardPageView*
296 BootManagerController::_CreateErrorEntryPage()
298 BString description;
300 if (fCollectPartitionsStatus == B_ENTRY_NOT_FOUND) {
301 description << B_TRANSLATE_COMMENT("Partition table not compatible",
302 "Title") << "\n\n"
303 << B_TRANSLATE("The partition table of the first hard disk is not "
304 "compatible with Boot Manager.\n"
305 "Boot Manager only works with IBM PC MBR partitions.");
306 } else if (fCollectPartitionsStatus == B_PARTITION_TOO_SMALL) {
307 description << B_TRANSLATE_COMMENT("First partition starts too early",
308 "Title") << "\n\n"
309 << B_TRANSLATE("The first partition on the disk starts too early "
310 "and does not leave enough space free for a boot menu.\n"
311 "Boot Manager needs 2 KiB available space before the first "
312 "partition.");
313 } else {
314 description << B_TRANSLATE_COMMENT("Error reading partition table",
315 "Title") << "\n\n"
316 << B_TRANSLATE("Boot Manager is unable to read the partition "
317 "table!");
320 return new DescriptionPage("errorEntry", description.String(), true);
324 WizardPageView*
325 BootManagerController::_CreateSaveMBRPage(BRect frame)
327 BString description;
328 BString disk;
329 fSettings.FindString("disk", &disk);
331 description << B_TRANSLATE_COMMENT("Backup Master Boot Record", "Title")
332 << "\n" << B_TRANSLATE("The Master Boot Record (MBR) of the boot "
333 "device:\n"
334 "\t%s\n"
335 "will now be saved to disk. Please select a file to "
336 "save the MBR into.\n\n"
337 "If something goes wrong with the installation or if "
338 "you later wish to remove the boot menu, simply run the "
339 "bootman program and choose the 'Uninstall' option.");
340 description.ReplaceFirst("%s", disk);
342 return new FileSelectionPage(&fSettings, frame, "saveMBR",
343 description.String(),
344 B_SAVE_PANEL);
348 WizardPageView*
349 BootManagerController::_CreateMBRSavedPage()
351 BString description;
352 BString file;
353 fSettings.FindString("file", &file);
355 if (fSaveMBRStatus == B_OK) {
356 description << B_TRANSLATE_COMMENT("Old Master Boot Record saved",
357 "Title") << "\n"
358 << B_TRANSLATE("The old Master Boot Record was successfully "
359 "saved to %s.") << "\n";
360 } else {
361 description << B_TRANSLATE_COMMENT("Old Master Boot Record backup "
362 "failure", "Title") << "\n"
363 << B_TRANSLATE("The old Master Boot Record could not be saved "
364 "to %s. You can continue the installation but there will be no "
365 "way to uninstall the boot menu.") << "\n";
367 description.ReplaceFirst("%s", file);
369 return new DescriptionPage("summary", description.String(), true);
373 WizardPageView*
374 BootManagerController::_CreateInstallSummaryPage()
376 BString description;
377 BString disk;
378 fSettings.FindString("disk", &disk);
380 description << B_TRANSLATE_COMMENT("Summary", "Title") << "\n"
381 << B_TRANSLATE("About to write the following boot menu to the boot "
382 "disk (%s). Please verify the information below before continuing.")
383 << "\n\n";
384 description.ReplaceFirst("%s", disk);
386 BMessage message;
387 for (int32 i = 0; fSettings.FindMessage("partition", i, &message) == B_OK;
388 i++) {
389 bool show;
390 if (message.FindBool("show", &show) != B_OK || !show)
391 continue;
393 BString name;
394 BString path;
395 message.FindString("name", &name);
396 message.FindString("path", &path);
398 BString displayName;
399 if (fBootMenu->GetDisplayText(name.String(), displayName) == B_OK)
400 description << displayName << "\t(" << path << ")\n";
401 else
402 description << name << "\t(" << path << ")\n";
405 return new DescriptionPage("summary", description.String(), true);
409 WizardPageView*
410 BootManagerController::_CreateInstalledPage()
412 BString description;
414 if (fWriteBootMenuStatus == B_OK) {
415 description << B_TRANSLATE_COMMENT("Installation of boot menu "
416 "completed", "Title") << "\n"
417 << B_TRANSLATE("The boot manager has been successfully installed "
418 "on your system.");
419 } else {
420 description << B_TRANSLATE_COMMENT("Installation of boot menu failed",
421 "Title") << "\n"
422 << B_TRANSLATE("An error occurred writing the boot menu. "
423 "The Master Boot Record might be destroyed, "
424 "you should restore the MBR now!");
427 return new DescriptionPage("done", description, true);
431 WizardPageView*
432 BootManagerController::_CreateUninstallPage(BRect frame)
434 BString description;
435 description << B_TRANSLATE_COMMENT("Uninstall boot manager", "Title")
436 << "\n\n"
437 << B_TRANSLATE("Please locate the Master Boot Record (MBR) save file "
438 "to restore from. This is the file that was created when the "
439 "boot manager was first installed.");
441 return new FileSelectionPage(&fSettings, frame, "restoreMBR",
442 description.String(), B_OPEN_PANEL);
446 WizardPageView*
447 BootManagerController::_CreateUninstalledPage()
449 BString description;
450 BString disk;
451 BString file;
452 fSettings.FindString("disk", &disk);
453 fSettings.FindString("file", &file);
455 if (fRestoreMBRStatus == B_OK) {
456 description << B_TRANSLATE_COMMENT("Uninstallation of boot menu "
457 "completed", "Title") << "\n"
458 << B_TRANSLATE("The Master Boot Record of the boot device "
459 "(%DISK) has been successfully restored from %FILE.");
460 description.ReplaceFirst("%DISK", disk);
461 description.ReplaceFirst("%FILE", file);
462 } else {
463 description << B_TRANSLATE_COMMENT("Uninstallation of boot menu "
464 "failed", "Title") << "\n"
465 << B_TRANSLATE("The Master Boot Record could not be restored!");
468 return new DescriptionPage("summary", description.String(), true);