1 /* 2 * Copyright 2008-2011, Haiku, Inc. All rights reserved. 3 * Distributed under the terms of the MIT License. 4 * 5 * Authors: 6 * Axel Dörfler, axeld@pinc-software.de 7 * Michael Pfeiffer <laplace@users.sourceforge.net> 8 */ 9 10 11 #include "BootManagerController.h" 12 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> 21 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" 30 31 32 #undef B_TRANSLATION_CONTEXT 33 #define B_TRANSLATION_CONTEXT "BootManagerController" 34 35 36 BootManagerController::BootManagerController() 37 : 38 fBootDrive(NULL), 39 fBootMenu(NULL) 40 { 41 // set defaults 42 fSettings.AddBool("install", true); 43 fSettings.AddInt32("defaultPartition", 0); 44 fSettings.AddInt32("timeout", -1); 45 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); 55 } 56 } else { 57 fSettings.AddString("file", ""); 58 } 59 60 // That's the only boot menu we support at the moment. 61 fBootMenus.AddItem(new LegacyBootMenu()); 62 } 63 64 65 BootManagerController::~BootManagerController() 66 { 67 } 68 69 70 void 71 BootManagerController::Previous(WizardView* wizard) 72 { 73 if (CurrentState() != kStateEntry) 74 WizardController::Previous(wizard); 75 else { 76 fSettings.ReplaceBool("install", false); 77 WizardController::Next(wizard); 78 } 79 } 80 81 82 int32 83 BootManagerController::InitialState() 84 { 85 return kStateEntry; 86 } 87 88 89 int32 90 BootManagerController::NextState(int32 state) 91 { 92 switch (state) { 93 case kStateEntry: 94 { 95 const char* path; 96 if (fSettings.FindString("disk", &path) != B_OK) 97 return kStateErrorEntry; 98 99 delete fBootDrive; 100 101 fBootDrive = new BootDrive(path); 102 fBootMenu = fBootDrive->InstalledMenu(fBootMenus); 103 104 if (fSettings.FindBool("install")) { 105 int32 nextState = fBootMenu != NULL 106 ? kStatePartitions : kStateSaveMBR; 107 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); 113 114 fCollectPartitionsStatus = fBootMenu->CollectPartitions( 115 *fBootDrive, fSettings); 116 117 return nextState; 118 } 119 120 return kStateUninstall; 121 } 122 123 case kStateErrorEntry: 124 be_app->PostMessage(B_QUIT_REQUESTED); 125 break; 126 127 case kStateSaveMBR: 128 if (_SaveMBR()) 129 return kStateMBRSaved; 130 break; 131 132 case kStateMBRSaved: 133 return kStatePartitions; 134 135 case kStatePartitions: 136 if (_HasSelectedPartitions()) 137 return kStateDefaultPartitions; 138 break; 139 140 case kStateDefaultPartitions: 141 return kStateInstallSummary; 142 143 case kStateInstallSummary: 144 if (_WriteBootMenu()) 145 return kStateInstalled; 146 break; 147 148 case kStateInstalled: 149 be_app->PostMessage(B_QUIT_REQUESTED); 150 break; 151 152 case kStateUninstall: 153 if (_RestoreMBR()) 154 return kStateUninstalled; 155 break; 156 157 case kStateUninstalled: 158 be_app->PostMessage(B_QUIT_REQUESTED); 159 break; 160 } 161 // cannot leave the current state/page 162 return -1; 163 } 164 165 166 bool 167 BootManagerController::_HasSelectedPartitions() 168 { 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; 175 } 176 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(); 182 183 return false; 184 } 185 186 187 bool 188 BootManagerController::_WriteBootMenu() 189 { 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); 195 196 if (alert->Go() == 1) 197 return false; 198 199 fWriteBootMenuStatus = fBootMenu->Install(*fBootDrive, fSettings); 200 return true; 201 } 202 203 204 bool 205 BootManagerController::_SaveMBR() 206 { 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; 212 } 213 214 215 bool 216 BootManagerController::_RestoreMBR() 217 { 218 BString disk; 219 BString path; 220 fSettings.FindString("disk", &disk); 221 fSettings.FindString("file", &path); 222 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); 229 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; 236 237 BFile file(path.String(), B_READ_ONLY); 238 fRestoreMBRStatus = fBootMenu->RestoreMasterBootRecord(&fSettings, &file); 239 return true; 240 } 241 242 243 WizardPageView* 244 BootManagerController::CreatePage(int32 state, WizardView* wizard) 245 { 246 WizardPageView* page = NULL; 247 BRect frame(0, 0, 300, 250); 248 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; 289 } 290 291 return page; 292 } 293 294 295 WizardPageView* 296 BootManagerController::_CreateErrorEntryPage() 297 { 298 BString description; 299 300 if (fCollectPartitionsStatus == B_PARTITION_TOO_SMALL) { 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 needs 2 KB available space before the first " 306 "partition."); 307 } else { 308 description << B_TRANSLATE_COMMENT("Error reading partition table", 309 "Title") << "\n\n" 310 << B_TRANSLATE("Boot Manager is unable to read the partition " 311 "table!"); 312 } 313 314 return new DescriptionPage("errorEntry", description.String(), true); 315 } 316 317 318 WizardPageView* 319 BootManagerController::_CreateSaveMBRPage(BRect frame) 320 { 321 BString description; 322 BString disk; 323 fSettings.FindString("disk", &disk); 324 325 description << B_TRANSLATE_COMMENT("Backup Master Boot Record", "Title") 326 << "\n" << B_TRANSLATE("The Master Boot Record (MBR) of the boot " 327 "device:\n" 328 "\t%s\n" 329 "will now be saved to disk. Please select a file to " 330 "save the MBR into.\n\n" 331 "If something goes wrong with the installation or if " 332 "you later wish to remove the boot menu, simply run the " 333 "bootman program and choose the 'Uninstall' option."); 334 description.ReplaceFirst("%s", disk); 335 336 return new FileSelectionPage(&fSettings, frame, "saveMBR", 337 description.String(), 338 B_SAVE_PANEL); 339 } 340 341 342 WizardPageView* 343 BootManagerController::_CreateMBRSavedPage() 344 { 345 BString description; 346 BString file; 347 fSettings.FindString("file", &file); 348 349 if (fSaveMBRStatus == B_OK) { 350 description << B_TRANSLATE_COMMENT("Old Master Boot Record saved", 351 "Title") << "\n" 352 << B_TRANSLATE("The old Master Boot Record was successfully " 353 "saved to %s.") << "\n"; 354 } else { 355 description << B_TRANSLATE_COMMENT("Old Master Boot Record Saved " 356 "failure", "Title") << "\n" 357 << B_TRANSLATE("The old Master Boot Record could not be saved " 358 "to %s") << "\n"; 359 } 360 description.ReplaceFirst("%s", file); 361 362 return new DescriptionPage("summary", description.String(), true); 363 } 364 365 366 WizardPageView* 367 BootManagerController::_CreateInstallSummaryPage() 368 { 369 BString description; 370 BString disk; 371 fSettings.FindString("disk", &disk); 372 373 description << B_TRANSLATE_COMMENT("Summary", "Title") << "\n" 374 << B_TRANSLATE("About to write the following boot menu to the boot " 375 "disk (%s). Please verify the information below before continuing.") 376 << "\n\n"; 377 description.ReplaceFirst("%s", disk); 378 379 BMessage message; 380 for (int32 i = 0; fSettings.FindMessage("partition", i, &message) == B_OK; 381 i++) { 382 bool show; 383 if (message.FindBool("show", &show) != B_OK || !show) 384 continue; 385 386 BString name; 387 BString path; 388 message.FindString("name", &name); 389 message.FindString("path", &path); 390 391 BString displayName; 392 if (fBootMenu->GetDisplayText(name.String(), displayName) == B_OK) 393 description << displayName << "\t(" << path << ")\n"; 394 else 395 description << name << "\t(" << path << ")\n"; 396 } 397 398 return new DescriptionPage("summary", description.String(), true); 399 } 400 401 402 WizardPageView* 403 BootManagerController::_CreateInstalledPage() 404 { 405 BString description; 406 407 if (fWriteBootMenuStatus == B_OK) { 408 description << B_TRANSLATE_COMMENT("Installation of boot menu " 409 "completed", "Title") << "\n" 410 << B_TRANSLATE("The boot manager has been successfully installed " 411 "on your system."); 412 } else { 413 description << B_TRANSLATE_COMMENT("Installation of boot menu failed", 414 "Title") << "\n" 415 << B_TRANSLATE("An error occurred writing the boot menu. " 416 "The Master Boot Record might be destroyed, " 417 "you should restore the MBR now!"); 418 } 419 420 return new DescriptionPage("done", description, true); 421 } 422 423 424 WizardPageView* 425 BootManagerController::_CreateUninstallPage(BRect frame) 426 { 427 BString description; 428 description << B_TRANSLATE_COMMENT("Uninstall boot manager", "Title") 429 << "\n\n" 430 << B_TRANSLATE("Please locate the Master Boot Record (MBR) save file " 431 "to restore from. This is the file that was created when the " 432 "boot manager was first installed."); 433 434 return new FileSelectionPage(&fSettings, frame, "restoreMBR", 435 description.String(), B_OPEN_PANEL); 436 } 437 438 439 WizardPageView* 440 BootManagerController::_CreateUninstalledPage() 441 { 442 BString description; 443 BString disk; 444 BString file; 445 fSettings.FindString("disk", &disk); 446 fSettings.FindString("file", &file); 447 448 if (fRestoreMBRStatus == B_OK) { 449 description << B_TRANSLATE_COMMENT("Uninstallation of boot menu " 450 "completed", "Title") << "\n" 451 << B_TRANSLATE("The Master Boot Record of the boot device " 452 "(%DISK) has been successfully restored from %FILE."); 453 description.ReplaceFirst("%DISK", disk); 454 description.ReplaceFirst("%FILE", file); 455 } else { 456 description << B_TRANSLATE_COMMENT("Uninstallation of boot menu " 457 "failed", "Title") << "\n" 458 << B_TRANSLATE("The Master Boot Record could not be restored!"); 459 } 460 461 return new DescriptionPage("summary", description.String(), true); 462 } 463