diff --git a/src/apps/bootman/BootDrive.h b/src/apps/bootman/BootDrive.h index 122e3dc966..906417dd55 100644 --- a/src/apps/bootman/BootDrive.h +++ b/src/apps/bootman/BootDrive.h @@ -23,17 +23,23 @@ "path" String (path to partition in /dev/...) "size" long (size of partition in bytes) */ + +enum { + // Not enough space free before first partition for boot loader + kErrorBootSectorTooSmall = B_ERRORS_END + 1, +}; + class BootDrive { public: BootDrive() {} virtual ~BootDrive() {} - virtual bool IsBootMenuInstalled() = 0; - virtual status_t ReadPartitions(BMessage *message) = 0; - virtual status_t WriteBootMenu(BMessage *message) = 0; - virtual status_t SaveMasterBootRecord(BFile *file) = 0; - virtual status_t RestoreMasterBootRecord(BFile *file) = 0; + virtual bool IsBootMenuInstalled(BMessage* settings) = 0; + virtual status_t ReadPartitions(BMessage* settings) = 0; + virtual status_t WriteBootMenu(BMessage* settings) = 0; + virtual status_t SaveMasterBootRecord(BMessage* settings, BFile* file) = 0; + virtual status_t RestoreMasterBootRecord(BMessage* settings, BFile* file) = 0; }; #endif // BOOT_DRIVE_H diff --git a/src/apps/bootman/BootLoader.h b/src/apps/bootman/BootLoader.h new file mode 100644 index 0000000000..87f03d84e4 --- /dev/null +++ b/src/apps/bootman/BootLoader.h @@ -0,0 +1,69 @@ +// THIS FILE WAS GENERATED WITH +// ./make_array kBootLoader bootman.bin + +static const uint8 kBootLoader[] = { + 0xb8, 0xc0, 0x07, 0x8e, 0xd8, 0x8e, 0xc0, 0x8e, 0xd0, 0xbc, 0xff, 0xff, 0xfc, 0xb4, 0x06, 0x30, + 0xc0, 0xb7, 0x0f, 0x31, 0xc9, 0xba, 0x4f, 0x18, 0xcd, 0x10, 0xb7, 0x00, 0xb4, 0x02, 0xba, 0x1f, + 0x01, 0xcd, 0x10, 0xbe, 0x83, 0x00, 0xb3, 0x0f, 0xe8, 0x2c, 0x00, 0xb4, 0x02, 0xba, 0x1b, 0x17, + 0xb3, 0x07, 0xcd, 0x10, 0xbe, 0x96, 0x00, 0xe8, 0x1d, 0x00, 0xb4, 0x42, 0xb2, 0x80, 0xbe, 0x73, + 0x00, 0xcd, 0x13, 0x72, 0x03, 0xe9, 0xb8, 0x01, 0xbe, 0xb1, 0x00, 0xb3, 0x04, 0xe8, 0x07, 0x00, + 0xb4, 0x00, 0xcd, 0x16, 0xf4, 0xeb, 0xf9, 0x51, 0xe9, 0x11, 0x00, 0xb9, 0x01, 0x00, 0xb4, 0x09, + 0xcd, 0x10, 0xb4, 0x03, 0xcd, 0x10, 0xfe, 0xc2, 0xb4, 0x02, 0xcd, 0x10, 0xac, 0x3c, 0x00, 0x75, + 0xea, 0x59, 0xc3, 0x10, 0x00, 0x03, 0x00, 0x00, 0x02, 0xc0, 0x07, 0x01, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x48, 0x61, 0x69, 0x6b, 0x75, 0x20, 0x42, 0x6f, 0x6f, 0x74, 0x20, 0x4d, 0x61, + 0x6e, 0x61, 0x67, 0x65, 0x72, 0x00, 0x53, 0x65, 0x6c, 0x65, 0x63, 0x74, 0x20, 0x61, 0x6e, 0x20, + 0x4f, 0x53, 0x20, 0x66, 0x72, 0x6f, 0x6d, 0x20, 0x74, 0x68, 0x65, 0x20, 0x6d, 0x65, 0x6e, 0x75, + 0x00, 0x45, 0x72, 0x72, 0x6f, 0x72, 0x20, 0x6c, 0x6f, 0x61, 0x64, 0x69, 0x6e, 0x67, 0x20, 0x73, + 0x65, 0x63, 0x74, 0x6f, 0x72, 0x73, 0x21, 0x00, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, + 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, + 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, + 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, + 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, + 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, + 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, + 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, + 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, + 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, + 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, + 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, + 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, + 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, + 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, + 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, + 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, + 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, + 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, + 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x55, 0xaa, + 0xa1, 0x99, 0x03, 0xa3, 0x46, 0x03, 0xb8, 0x13, 0x00, 0xf7, 0x26, 0x9b, 0x03, 0x89, 0xd3, 0x50, + 0xb4, 0x00, 0xcd, 0x1a, 0x58, 0x01, 0xd0, 0x11, 0xcb, 0xa3, 0x4a, 0x03, 0x89, 0x1e, 0x4c, 0x03, + 0xa0, 0x97, 0x03, 0xd0, 0xe8, 0xb3, 0x0c, 0x28, 0xc3, 0x88, 0x1e, 0x48, 0x03, 0xe8, 0x65, 0x00, + 0x81, 0x3e, 0x9b, 0x03, 0xff, 0xff, 0x74, 0x27, 0xb4, 0x01, 0xcd, 0x16, 0x75, 0x21, 0xe8, 0x05, + 0x00, 0x73, 0xf5, 0xe9, 0x9b, 0x00, 0xb4, 0x00, 0xcd, 0x1a, 0x3b, 0x0e, 0x4c, 0x03, 0x72, 0x08, + 0x77, 0x08, 0x3b, 0x16, 0x4a, 0x03, 0x77, 0x02, 0xf8, 0xc3, 0xf9, 0xc3, 0xe8, 0x36, 0x00, 0xb4, + 0x00, 0xcd, 0x16, 0x80, 0xfc, 0x50, 0x74, 0x0c, 0x80, 0xfc, 0x48, 0x74, 0x18, 0x80, 0xfc, 0x1c, + 0x74, 0x6f, 0xeb, 0xeb, 0xa1, 0x46, 0x03, 0x40, 0x3b, 0x06, 0x97, 0x03, 0x75, 0x02, 0x31, 0xc0, + 0xa3, 0x46, 0x03, 0xeb, 0xd7, 0xa1, 0x46, 0x03, 0x09, 0xc0, 0x75, 0x03, 0xa1, 0x97, 0x03, 0x48, + 0xa3, 0x46, 0x03, 0xeb, 0xc7, 0xa0, 0x48, 0x03, 0xa2, 0x49, 0x03, 0xbe, 0x9d, 0x03, 0x31, 0xc9, + 0xac, 0xfe, 0xc8, 0xd0, 0xe8, 0xb2, 0x28, 0x28, 0xc2, 0x8a, 0x36, 0x49, 0x03, 0xb4, 0x02, 0xcd, + 0x10, 0x89, 0xcf, 0x81, 0xe7, 0x03, 0x00, 0x8a, 0x9d, 0x5e, 0x03, 0x3b, 0x0e, 0x46, 0x03, 0x75, + 0x03, 0x80, 0xf3, 0x08, 0xe8, 0x56, 0x00, 0x81, 0xc6, 0x08, 0x00, 0xfe, 0x06, 0x49, 0x03, 0x41, + 0x3b, 0x0e, 0x97, 0x03, 0x75, 0xca, 0xb4, 0x02, 0xba, 0x1a, 0x15, 0xba, 0x1c, 0x18, 0xcd, 0x10, + 0xc3, 0xbe, 0x9d, 0x03, 0x8b, 0x0e, 0x46, 0x03, 0x41, 0x30, 0xe4, 0xe9, 0x04, 0x00, 0x81, 0xc6, + 0x08, 0x00, 0xac, 0x01, 0xc6, 0xe2, 0xf7, 0xbf, 0x56, 0x03, 0xb9, 0x04, 0x00, 0xad, 0xab, 0xe2, + 0xfc, 0xb4, 0x42, 0xb2, 0x80, 0xbe, 0x4e, 0x03, 0xcd, 0x13, 0xbe, 0x62, 0x03, 0x72, 0x2a, 0xa1, + 0xfe, 0x01, 0x3d, 0x55, 0xaa, 0xbe, 0x78, 0x03, 0x75, 0x1f, 0xe9, 0xe3, 0xfc, 0x51, 0xe9, 0x11, + 0x00, 0xb9, 0x01, 0x00, 0xb4, 0x09, 0xcd, 0x10, 0xb4, 0x03, 0xcd, 0x10, 0xfe, 0xc2, 0xb4, 0x02, + 0xcd, 0x10, 0xac, 0x3c, 0x00, 0x75, 0xea, 0x59, 0xc3, 0xbb, 0x0f, 0x00, 0xe8, 0xde, 0xff, 0xb4, + 0x00, 0xcd, 0x16, 0xf4, 0xeb, 0xf9, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, + 0x01, 0x00, 0x00, 0x00, 0xc0, 0x07, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x04, + 0x03, 0x02, 0x45, 0x72, 0x72, 0x6f, 0x72, 0x20, 0x6c, 0x6f, 0x61, 0x64, 0x69, 0x6e, 0x67, 0x20, + 0x73, 0x65, 0x63, 0x74, 0x6f, 0x72, 0x73, 0x00, 0x4e, 0x6f, 0x74, 0x20, 0x61, 0x20, 0x62, 0x6f, + 0x6f, 0x74, 0x61, 0x62, 0x6c, 0x65, 0x20, 0x70, 0x61, 0x72, 0x74, 0x69, 0x74, 0x69, 0x6f, 0x6e, + 0x00, 0x42, 0x6f, 0x6f, 0x74, 0x21, 0x00, 0x06, 0x00, 0x02, 0x00, 0x05, 0x00, 0x06, 0x48, 0x41, + 0x49, 0x4b, 0x55, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x08, 0x46, 0x72, 0x65, + 0x65, 0x42, 0x53, 0x44, 0x00, 0x3f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0x44, 0x4f, + 0x53, 0x00, 0x3e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x06, 0x4c, 0x49, 0x4e, 0x55, 0x58, + 0x00, 0x3f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x08, 0x42, 0x65, 0x4f, 0x53, 0x20, 0x52, + 0x35, 0x00, 0x3f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x07, 0x4f, 0x70, 0x65, 0x6e, 0x42, + 0x53, 0x44, 0x00, 0xaa, 0xaa, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 +}; diff --git a/src/apps/bootman/BootManagerController.cpp b/src/apps/bootman/BootManagerController.cpp index 91fad4cf87..c8ac973e94 100644 --- a/src/apps/bootman/BootManagerController.cpp +++ b/src/apps/bootman/BootManagerController.cpp @@ -61,7 +61,7 @@ BootManagerController::BootManagerController() fSettings.AddString("file", ""); } - fBootDrive->ReadPartitions(&fSettings); + fReadPartitionsStatus = fBootDrive->ReadPartitions(&fSettings); } @@ -73,7 +73,9 @@ BootManagerController::~BootManagerController() int32 BootManagerController::InitialState() { - return kStateEntry; + if (fReadPartitionsStatus == B_OK) + return kStateEntry; + return kStateErrorEntry; } @@ -86,7 +88,7 @@ BootManagerController::NextState(int32 state) bool install; fSettings.FindBool("install", &install); if (install) { - if (fBootDrive->IsBootMenuInstalled()) + if (fBootDrive->IsBootMenuInstalled(&fSettings)) return kStatePartitions; else return kStateSaveMBR; @@ -94,6 +96,10 @@ BootManagerController::NextState(int32 state) else return kStateUninstall; } + + case kStateErrorEntry: + be_app->PostMessage(B_QUIT_REQUESTED); + break; case kStateSaveMBR: if (_SaveMBR()) @@ -162,10 +168,7 @@ BootManagerController::_WriteBootMenu() if (alert->Go() == 1) return false; - status_t status = fBootDrive->WriteBootMenu(&fSettings); - fSettings.RemoveName("installStatus"); - fSettings.AddInt32("installStatus", status); - + fWriteBootMenuStatus = fBootDrive->WriteBootMenu(&fSettings); return true; } @@ -173,11 +176,10 @@ BootManagerController::_WriteBootMenu() bool BootManagerController::_SaveMBR() { - BFile file("", B_READ_WRITE | B_CREATE_FILE | B_ERASE_FILE); - status_t state = fBootDrive->SaveMasterBootRecord(&file); - fSettings.RemoveName("saveMBRStatus"); - fSettings.AddInt32("saveMBRStatus", state); - + BString path; + fSettings.FindString("file", &path); + BFile file(path.String(), B_READ_WRITE | B_CREATE_FILE | B_ERASE_FILE); + fSaveMBRStatus = fBootDrive->SaveMasterBootRecord(&fSettings, &file); return true; } @@ -201,10 +203,7 @@ BootManagerController::_RestoreMBR() return false; BFile file(path.String(), B_READ_ONLY); - status_t state = fBootDrive->RestoreMasterBootRecord(&file); - fSettings.RemoveName("restoreMBRStatus"); - fSettings.AddInt32("restoreMBRStatus", state); - + fRestoreMBRStatus = fBootDrive->RestoreMasterBootRecord(&fSettings, &file); return true; } @@ -220,6 +219,11 @@ BootManagerController::CreatePage(int32 state, WizardView* wizard) page = new EntryPage(&fSettings, frame, "entry"); wizard->SetPreviousButtonHidden(true); break; + case kStateErrorEntry: + page = _CreateErrorEntryPage(frame); + wizard->SetPreviousButtonHidden(true); + wizard->SetNextButtonLabel("Done"); + break; case kStateSaveMBR: page = _CreateSaveMBRPage(frame); wizard->SetPreviousButtonHidden(false); @@ -258,6 +262,26 @@ BootManagerController::CreatePage(int32 state, WizardView* wizard) } +WizardPageView* +BootManagerController::_CreateErrorEntryPage(BRect frame) +{ + BString description; + + if (fReadPartitionsStatus == kErrorBootSectorTooSmall) + description << + "Partition Table Not Compatible\n\n" + "The partition table of the first hard disk is not compatible " + "with Boot Manager.\n" + "Boot Manager needs 2 KB available space before the first partition."; + else + description << + "Error Reading Partition Table\n\n" + "Boot Manager is unable to read the partition table!"; + + return new DescriptionPage(frame, "errorEntry", description.String(), true); +} + + WizardPageView* BootManagerController::_CreateSaveMBRPage(BRect frame) { @@ -275,9 +299,8 @@ BootManagerController::_CreateSaveMBRPage(BRect frame) "you later wish to remove the boot menu, simply run the " "bootman program and choose to 'Uninstall' option."; - FileSelectionPage* page = new FileSelectionPage(&fSettings, frame, "saveMBR", description.String(), + return new FileSelectionPage(&fSettings, frame, "saveMBR", description.String(), B_SAVE_PANEL); - return page; } @@ -288,13 +311,19 @@ BootManagerController::_CreateMBRSavedPage(BRect frame) BString file; fSettings.FindString("file", &file); - description << - "Old Master Boot Record Saved\n\n" - "The old Master Boot Record was successfully save to " - << file << ".\n"; + if (fSaveMBRStatus == B_OK) { + description << + "Old Master Boot Record Saved\n\n" + "The old Master Boot Record was successfully save to " + << file << ".\n"; + } else { + description << + "Old Master Boot Record Saved Failure\n\n" + "The old Master Boot Record could not be saved to " + << file << ".\n"; + } - DescriptionPage* page = new DescriptionPage(frame, "summary", description.String(), true); - return page; + return new DescriptionPage(frame, "summary", description.String(), true); } @@ -325,8 +354,7 @@ BootManagerController::_CreateInstallSummaryPage(BRect frame) description << name << "\t(" << path << ")\n"; } - DescriptionPage* page = new DescriptionPage(frame, "summary", description.String(), true); - return page; + return new DescriptionPage(frame, "summary", description.String(), true); } @@ -335,20 +363,17 @@ BootManagerController::_CreateInstalledPage(BRect frame) { const char* description; - int32 status; - fSettings.FindInt32("installStatus", &status); - if (status == B_OK) { + if (fWriteBootMenuStatus == B_OK) { description = "Installation Boot Menu Completed\n\n" "The boot manager has been successfully installed " "on your system."; } else { - // TODO description = "Installation Boot Menu Failed\n\n" - "TODO"; + "An error occured writing the boot menu. The Master Boot Record " + "might be destroyed, you should restore the MBR now!"; } - DescriptionPage* page = new DescriptionPage(frame, "done", description, true); - return page; + return new DescriptionPage(frame, "done", description, true); } @@ -363,9 +388,8 @@ BootManagerController::_CreateUninstallPage(BRect frame) "restore from. This is the file that was created when the " "boot manager was first installed."; - FileSelectionPage* page = new FileSelectionPage(&fSettings, frame, "restoreMBR", description.String(), + return new FileSelectionPage(&fSettings, frame, "restoreMBR", description.String(), B_OPEN_PANEL); - return page; } @@ -378,22 +402,17 @@ BootManagerController::_CreateUninstalledPage(BRect frame) fSettings.FindString("disk", &disk); fSettings.FindString("file", &file); - int32 status; - fSettings.FindInt32("restoreMBRStatus", &status); - if (status == B_OK) { + if (fRestoreMBRStatus == B_OK) { description << "Uninstallation Boot Menu Completed\n\n" "The Master Boot Record of the boot device " "(" << disk << ") has been successfully restored from " << file << "."; } else { - // TODO description << "Uninstallation Boot Menu Failed\n\n" - "TODO"; + "The Master Boot Record could not be restored!"; } - DescriptionPage* page = new DescriptionPage(frame, "summary", description.String(), true); - return page; - + return new DescriptionPage(frame, "summary", description.String(), true); } diff --git a/src/apps/bootman/BootManagerController.h b/src/apps/bootman/BootManagerController.h index d15217c6d8..f36bb1969f 100644 --- a/src/apps/bootman/BootManagerController.h +++ b/src/apps/bootman/BootManagerController.h @@ -25,9 +25,6 @@ class BRect; "file" String (the file where the backup of the MBR is saved) "defaultPartition" int32 (index of default partition) "timeout" int32 (timeout in seconds, -1 for no timeout) - "installStatus" int32 (status_t) - "saveMBRStatus" int32 (status_t) - "restoreMBRStatus" int32 (status_t) */ class BootManagerController : public WizardController @@ -45,6 +42,7 @@ private: enum State { kStateEntry, + kStateErrorEntry, // Install states kStateSaveMBR, @@ -64,6 +62,7 @@ private: bool _SaveMBR(); bool _RestoreMBR(); + WizardPageView* _CreateErrorEntryPage(BRect frame); WizardPageView* _CreateSaveMBRPage(BRect frame); WizardPageView* _CreateMBRSavedPage(BRect frame); WizardPageView* _CreateInstallSummaryPage(BRect frame); @@ -73,6 +72,11 @@ private: BMessage fSettings; BootDrive* fBootDrive; + + status_t fReadPartitionsStatus; + status_t fWriteBootMenuStatus; + status_t fSaveMBRStatus; + status_t fRestoreMBRStatus; }; diff --git a/src/apps/bootman/Jamfile b/src/apps/bootman/Jamfile index e035569d17..26a748d7b3 100644 --- a/src/apps/bootman/Jamfile +++ b/src/apps/bootman/Jamfile @@ -13,7 +13,6 @@ Application bootman : FileSelectionPage.cpp LegacyBootDrive.cpp PartitionsPage.cpp - TestBootDrive.cpp UninstallPage.cpp WizardController.cpp WizardPageView.cpp diff --git a/src/apps/bootman/LegacyBootDrive.cpp b/src/apps/bootman/LegacyBootDrive.cpp index 614a5519ba..9e73f12922 100644 --- a/src/apps/bootman/LegacyBootDrive.cpp +++ b/src/apps/bootman/LegacyBootDrive.cpp @@ -17,7 +17,93 @@ #include #include +#include +#include #include +#include +#include +#include + +#include +#include +#include +#include + +#include "BootLoader.h" + + +#define USE_SECOND_DISK 0 + + +class Buffer : public BMallocIO +{ +public: + Buffer() : BMallocIO() {} + bool WriteInt8(int8 value); + bool WriteInt16(int16 value); + bool WriteInt32(int32 value); + bool WriteInt64(int64 value); + bool WriteString(const char* value); + bool Align(int16 alignment); + bool Fill(int16 size, int8 fillByte); +}; + + +bool +Buffer::WriteInt8(int8 value) +{ + return Write(&value, sizeof(value)) == sizeof(value); +} + + +bool +Buffer::WriteInt16(int16 value) +{ + return WriteInt8(value & 0xff) && WriteInt8(value >> 8); +} + + +bool +Buffer::WriteInt32(int32 value) +{ + return WriteInt8(value & 0xff) && WriteInt8(value >> 8) && + WriteInt8(value >> 16) && WriteInt8(value >> 24); +} + + +bool +Buffer::WriteInt64(int64 value) +{ + return WriteInt32(value) && WriteInt32(value >> 32); +} + + +bool +Buffer::WriteString(const char* value) +{ + int len = strlen(value) + 1; + return WriteInt8(len) && Write(value, len) == len; +} + + +bool +Buffer::Align(int16 alignment) +{ + if ((Position() % alignment) == 0) + return true; + return Fill(alignment - (Position() % alignment), 0); +} + + +bool +Buffer::Fill(int16 size, int8 fillByte) +{ + for (int i = 0; i < size; i ++) { + if (!WriteInt8(fillByte)) + return false; + } + return true; +} class PartitionRecorder : public BDiskDeviceVisitor @@ -28,16 +114,22 @@ public: virtual bool Visit(BDiskDevice* device); virtual bool Visit(BPartition* partition, int32 level); + bool HasPartitions() const; + off_t FirstOffset() const; + private: bool _Record(BPartition* partition); BMessage* fSettings; int32 fIndex; + off_t fFirstOffset; }; PartitionRecorder::PartitionRecorder(BMessage* settings) : fSettings(settings) + , fIndex(0) + , fFirstOffset((off_t)-1) { } @@ -56,6 +148,20 @@ PartitionRecorder::Visit(BPartition* partition, int32 level) } +bool +PartitionRecorder::HasPartitions() const +{ + return fFirstOffset != (off_t)-1; +} + + +off_t +PartitionRecorder::FirstOffset() const +{ + return fFirstOffset; +} + + bool PartitionRecorder::_Record(BPartition* partition) { @@ -75,13 +181,20 @@ PartitionRecorder::_Record(BPartition* partition) type = "Unknown"; BMessage message; + // Data as required by BootLoader.h message.AddBool("show", true); message.AddString("name", name); message.AddString("type", type); message.AddString("path", partitionPath.Path()); message.AddInt64("size", partition->ContentSize()); - fSettings->AddMessage("partition", &message); + // Specific data + message.AddInt64("offset", partition->Offset()); + + fSettings->AddMessage("partition", &message); + if (partition->Offset() < fFirstOffset) + fFirstOffset = partition->Offset(); + return false; } @@ -97,62 +210,279 @@ LegacyBootDrive::~LegacyBootDrive() bool -LegacyBootDrive::IsBootMenuInstalled() +LegacyBootDrive::IsBootMenuInstalled(BMessage* settings) { + // TODO detect bootman return false; } status_t -LegacyBootDrive::ReadPartitions(BMessage *message) +LegacyBootDrive::ReadPartitions(BMessage *settings) { BDiskDeviceRoster diskDeviceRoster; BDiskDevice device; - // first disk only - if (diskDeviceRoster.GetNextDevice(&device) == B_OK) { + bool diskFound = false; + while (diskDeviceRoster.GetNextDevice(&device) == B_OK) { BPath path; if (device.GetPath(&path) != B_OK) return B_ERROR; - - message->AddString("disk", path.Path()); - - - PartitionRecorder recorder(message); + + PartitionRecorder recorder(settings); device.VisitEachDescendant(&recorder); + + if (!diskFound) { + settings->AddString("disk", path.Path()); + diskFound = true; + + #if not USE_SECOND_DISK + // ignored in test build + off_t size = sizeof(kBootLoader); + if (!recorder.HasPartitions() || recorder.FirstOffset() < size) + return kErrorBootSectorTooSmall; + #endif + } } - return B_OK; + + #if USE_SECOND_DISK + // for testing only write boot menu to second hdd + settings->ReplaceString("disk", "/dev/disk/ata/1/master/raw"); + #endif + + if (diskFound) + return B_OK; + else + return B_ERROR; } status_t -LegacyBootDrive::WriteBootMenu(BMessage *message) +LegacyBootDrive::WriteBootMenu(BMessage *settings) { - // TODO printf("WriteBootMenu:\n"); - message->PrintToStream(); + settings->PrintToStream(); + + BString path; + if (settings->FindString("disk", &path) != B_OK) + return B_BAD_VALUE; - BMessage partition; - int32 index = 0; - for (; message->FindMessage("partition", index, &partition) == B_OK; index ++) { - printf("Partition %d:\n", (int)index); - partition.PrintToStream(); + int32 defaultPartitionIndex; + if (settings->FindInt32("defaultPartition", &defaultPartitionIndex) != B_OK) + return B_BAD_VALUE; + + int32 timeout; + if (settings->FindInt32("timeout", &timeout) != B_OK) + return B_BAD_VALUE; + + int fd = open(path.String(), O_RDWR); + if (fd < 0) + return B_IO_ERROR; + + MasterBootRecord oldMBR; + if (read(fd, &oldMBR, sizeof(oldMBR)) != sizeof(oldMBR)) { + close(fd); + return B_IO_ERROR; } + if (!_IsValid(&oldMBR)) { + close(fd); + return B_BAD_VALUE; + } + + Buffer newBootLoader; + ssize_t size = sizeof(kBootLoader); + if (newBootLoader.Write(kBootLoader, size) != size) { + close(fd); + return B_NO_MEMORY; + } + + MasterBootRecord* newMBR = (MasterBootRecord*)newBootLoader.BMallocIO::Buffer(); + _CopyPartitionTable(newMBR, &oldMBR); + + int menuEntries = 0; + BMessage partition; + int32 index; + for (index = 0; settings->FindMessage("partition", index, &partition) == B_OK; index ++) { + bool show; + partition.FindBool("show", &show); + if (!show) + continue; + + menuEntries ++; + } + newBootLoader.WriteInt16(menuEntries); + newBootLoader.WriteInt16(defaultPartitionIndex); + newBootLoader.WriteInt16(timeout); + + + for (index = 0; settings->FindMessage("partition", index, &partition) == B_OK; index ++) { + bool show; + BString name; + BString path; + int64 offset; + partition.FindBool("show", &show); + partition.FindString("name", &name); + partition.FindString("path", &path); + // LegacyBootDrive provides offset in message as well + partition.FindInt64("offset", &offset); + if (!show) + continue; + + newBootLoader.WriteString(name.String()); + newBootLoader.WriteInt64(offset / kBlockSize); + } + + if (!newBootLoader.Align(kBlockSize)) { + close(fd); + return B_ERROR; + } + + lseek(fd, 0, SEEK_SET); + const uint8* buffer = (uint8*)newBootLoader.BMallocIO::Buffer(); + status_t status = _WriteBlocks(fd, buffer, newBootLoader.Position()); + close(fd); + return status; +} + + +status_t +LegacyBootDrive::SaveMasterBootRecord(BMessage* settings, BFile* file) +{ + BString path; + + if (settings->FindString("disk", &path) != B_OK) + return B_BAD_VALUE; + + int fd = open(path.String(), O_RDONLY); + if (fd < 0) + return B_IO_ERROR; + + ssize_t size = kBlockSize * kNumberOfBootLoaderBlocks; + uint8* buffer = new uint8[size]; + if (buffer == NULL) { + close(fd); + return B_NO_MEMORY; + } + + status_t status = _ReadBlocks(fd, buffer, size); + if (status != B_OK) { + close(fd); + delete buffer; + return B_IO_ERROR; + } + + MasterBootRecord* mbr = (MasterBootRecord*)buffer; + if (!_IsValid(mbr)) { + close(fd); + delete buffer; + return B_BAD_VALUE; + } + + if (file->Write(buffer, size) != size) + status = B_IO_ERROR; + delete buffer; + close(fd); + return status; +} + + +status_t +LegacyBootDrive::RestoreMasterBootRecord(BMessage* settings, BFile* file) +{ + BString path; + if (settings->FindString("disk", &path) != B_OK) + return B_BAD_VALUE; + + int fd = open(path.String(), O_RDWR); + if (fd < 0) + return B_IO_ERROR; + + MasterBootRecord oldMBR; + if (read(fd, &oldMBR, sizeof(oldMBR)) != sizeof(oldMBR)) { + close(fd); + return B_IO_ERROR; + } + if (!_IsValid(&oldMBR)) { + close(fd); + return B_BAD_VALUE; + } + + lseek(fd, 0, SEEK_SET); + + size_t size = kBlockSize * kNumberOfBootLoaderBlocks; + uint8* buffer = new uint8[size]; + if (buffer == NULL) { + close(fd); + return B_NO_MEMORY; + } + + if (file->Read(buffer, size) != (ssize_t)size) { + close(fd); + delete buffer; + return B_IO_ERROR; + } + + MasterBootRecord* newMBR = (MasterBootRecord*)buffer; + if (!_IsValid(newMBR)) { + close(fd); + delete buffer; + return B_BAD_VALUE; + } + + _CopyPartitionTable(newMBR, &oldMBR); + + status_t status = _WriteBlocks(fd, buffer, size); + delete buffer; + close(fd); + return status; +} + + +status_t +LegacyBootDrive::_ReadBlocks(int fd, uint8* buffer, size_t size) +{ + if (size % kBlockSize != 0) { + fprintf(stderr, "_ReadBlocks buffer size must be a multiple of %d\n", (int)kBlockSize); + return B_BAD_VALUE; + } + const size_t blocks = size / kBlockSize; + uint8* block = buffer; + for (size_t i = 0; i < blocks; i ++, block += kBlockSize) { + if (read(fd, block, kBlockSize) != (ssize_t)kBlockSize) + return B_IO_ERROR; + } return B_OK; } status_t -LegacyBootDrive::SaveMasterBootRecord(BFile *file) +LegacyBootDrive::_WriteBlocks(int fd, const uint8* buffer, size_t size) { - // TODO implement + if (size % kBlockSize != 0) { + fprintf(stderr, "_WriteBlocks buffer size must be a multiple of %d\n", (int)kBlockSize); + return B_BAD_VALUE; + } + const size_t blocks = size / kBlockSize; + const uint8* block = buffer; + for (size_t i = 0; i < blocks; i ++, block += kBlockSize) { + if (write(fd, block, kBlockSize) != (ssize_t)kBlockSize) + return B_IO_ERROR; + } return B_OK; } -status_t -LegacyBootDrive::RestoreMasterBootRecord(BFile *file) +void +LegacyBootDrive::_CopyPartitionTable(MasterBootRecord* destination, + const MasterBootRecord* source) { - // TODO implement - return B_OK; + memcpy(destination->partition, source->partition, sizeof(source->partition)); +} + + +bool +LegacyBootDrive::_IsValid(const MasterBootRecord* mbr) +{ + return mbr->signature[0] == (kMBRSignature & 0xff) && + mbr->signature[1] == (kMBRSignature >> 8); } diff --git a/src/apps/bootman/LegacyBootDrive.h b/src/apps/bootman/LegacyBootDrive.h index cbebfa789c..80c0b60110 100644 --- a/src/apps/bootman/LegacyBootDrive.h +++ b/src/apps/bootman/LegacyBootDrive.h @@ -10,17 +10,41 @@ #include "BootDrive.h" +#include + +const uint32 kBlockSize = 512; +// The number of blocks required to store the +// MBR including the Haiku boot loader. +const uint32 kNumberOfBootLoaderBlocks = 4; + +const uint32 kMBRSignature = 0xAA55; + +typedef struct { + uint8 bootLoader[440]; + uint8 diskSignature[4]; + uint8 reserved[2]; + uint8 partition[64]; + uint8 signature[2]; +} MasterBootRecord; + class LegacyBootDrive : public BootDrive { public: LegacyBootDrive(); virtual ~LegacyBootDrive(); - virtual bool IsBootMenuInstalled(); - virtual status_t ReadPartitions(BMessage *message); - virtual status_t WriteBootMenu(BMessage *message); - virtual status_t SaveMasterBootRecord(BFile *file); - virtual status_t RestoreMasterBootRecord(BFile *file); + virtual bool IsBootMenuInstalled(BMessage* settings); + virtual status_t ReadPartitions(BMessage* settings); + virtual status_t WriteBootMenu(BMessage* settings); + virtual status_t SaveMasterBootRecord(BMessage* settings, BFile* file); + virtual status_t RestoreMasterBootRecord(BMessage* settings, BFile* file); + +private: + status_t _ReadBlocks(int fd, uint8* buffer, size_t size); + status_t _WriteBlocks(int fd, const uint8* buffer, size_t size); + void _CopyPartitionTable(MasterBootRecord* destination, + const MasterBootRecord* source); + bool _IsValid(const MasterBootRecord* mbr); }; #endif // LEGACY_BOOT_DRIVE_H diff --git a/src/apps/bootman/TestBootDrive.cpp b/src/apps/bootman/TestBootDrive.cpp index 13424f284b..cd20ce1b1a 100644 --- a/src/apps/bootman/TestBootDrive.cpp +++ b/src/apps/bootman/TestBootDrive.cpp @@ -9,8 +9,19 @@ #include "TestBootDrive.h" - +#include +#include #include +#include +#include +#include + +#include +#include +#include +#include + +#include "BootLoader.h" TestBootDrive::TestBootDrive() @@ -24,16 +35,16 @@ TestBootDrive::~TestBootDrive() bool -TestBootDrive::IsBootMenuInstalled() +TestBootDrive::IsBootMenuInstalled(BMessage* settings) { return false; } status_t -TestBootDrive::ReadPartitions(BMessage *message) +TestBootDrive::ReadPartitions(BMessage *settings) { - message->AddString("disk", "/dev/disk/ide/ata/0/master/0/raw"); + settings->AddString("disk", "bootcylinder"); BMessage partition; @@ -42,7 +53,7 @@ TestBootDrive::ReadPartitions(BMessage *message) partition.AddString("type", "bfs"); partition.AddString("path", "/dev/disk/ide/ata/0/master/0/0_0"); partition.AddInt64("size", 3 * (int64)1024 * 1024 * 1024); - message->AddMessage("partition", &partition); + settings->AddMessage("partition", &partition); partition.MakeEmpty(); @@ -51,7 +62,7 @@ TestBootDrive::ReadPartitions(BMessage *message) partition.AddString("type", "dos"); partition.AddString("path", "/dev/disk/ide/ata/0/slave/0/0_0"); partition.AddInt64("size", 10 * (int64)1024 * 1024 * 1024); - message->AddMessage("partition", &partition); + settings->AddMessage("partition", &partition); partition.MakeEmpty(); partition.AddBool("show", true); @@ -59,21 +70,21 @@ TestBootDrive::ReadPartitions(BMessage *message) partition.AddString("type", "unknown"); partition.AddString("path", "/dev/disk/ide/ata/0/slave/0/0_1"); partition.AddInt64("size", 250 * (int64)1024 * 1024 * 1024); - message->AddMessage("partition", &partition); + settings->AddMessage("partition", &partition); return B_OK; } status_t -TestBootDrive::WriteBootMenu(BMessage *message) +TestBootDrive::WriteBootMenu(BMessage *settings) { printf("WriteBootMenu:\n"); - message->PrintToStream(); + settings->PrintToStream(); BMessage partition; int32 index = 0; - for (; message->FindMessage("partition", index, &partition) == B_OK; index ++) { + for (; settings->FindMessage("partition", index, &partition) == B_OK; index ++) { printf("Partition %d:\n", (int)index); partition.PrintToStream(); } @@ -83,14 +94,18 @@ TestBootDrive::WriteBootMenu(BMessage *message) status_t -TestBootDrive::SaveMasterBootRecord(BFile *file) -{ +TestBootDrive::SaveMasterBootRecord(BMessage* settings, BFile* file) +{ return B_OK; } status_t -TestBootDrive::RestoreMasterBootRecord(BFile *file) +TestBootDrive::RestoreMasterBootRecord(BMessage* settings, BFile* file) { return B_OK; } + + + + diff --git a/src/apps/bootman/TestBootDrive.h b/src/apps/bootman/TestBootDrive.h index 33807a602f..186845d7b4 100644 --- a/src/apps/bootman/TestBootDrive.h +++ b/src/apps/bootman/TestBootDrive.h @@ -16,11 +16,11 @@ public: TestBootDrive(); virtual ~TestBootDrive(); - virtual bool IsBootMenuInstalled(); - virtual status_t ReadPartitions(BMessage *message); - virtual status_t WriteBootMenu(BMessage *message); - virtual status_t SaveMasterBootRecord(BFile *file); - virtual status_t RestoreMasterBootRecord(BFile *file); + virtual bool IsBootMenuInstalled(BMessage* settings); + virtual status_t ReadPartitions(BMessage* settings); + virtual status_t WriteBootMenu(BMessage* settings); + virtual status_t SaveMasterBootRecord(BMessage* settings, BFile* file); + virtual status_t RestoreMasterBootRecord(BMessage* settings, BFile* file); }; #endif // TEST_BOOT_DRIVE_H