15675f44eSAxel Dörfler /* 25675f44eSAxel Dörfler * Copyright 2008-2011, Haiku, Inc. All rights reserved. 35675f44eSAxel Dörfler * Distributed under the terms of the MIT License. 45675f44eSAxel Dörfler * 55675f44eSAxel Dörfler * Authors: 649c044abSAxel Dörfler * Axel Dörfler, axeld@pinc-software.de 75675f44eSAxel Dörfler * Michael Pfeiffer <laplace@users.sourceforge.net> 85675f44eSAxel Dörfler */ 95675f44eSAxel Dörfler 105675f44eSAxel Dörfler 115675f44eSAxel Dörfler #include "LegacyBootMenu.h" 125675f44eSAxel Dörfler 135675f44eSAxel Dörfler #include <new> 1449c044abSAxel Dörfler 1549c044abSAxel Dörfler #include <errno.h> 165675f44eSAxel Dörfler #include <stdio.h> 175675f44eSAxel Dörfler 185675f44eSAxel Dörfler #include <Catalog.h> 195675f44eSAxel Dörfler #include <DataIO.h> 205675f44eSAxel Dörfler #include <DiskDevice.h> 215675f44eSAxel Dörfler #include <DiskDeviceRoster.h> 225675f44eSAxel Dörfler #include <DiskDeviceVisitor.h> 2349c044abSAxel Dörfler #include <Drivers.h> 245675f44eSAxel Dörfler #include <File.h> 255675f44eSAxel Dörfler #include <Partition.h> 265675f44eSAxel Dörfler #include <Path.h> 275675f44eSAxel Dörfler #include <String.h> 285675f44eSAxel Dörfler #include <UTF8.h> 295675f44eSAxel Dörfler 3049c044abSAxel Dörfler #include "BootDrive.h" 315675f44eSAxel Dörfler #include "BootLoader.h" 325675f44eSAxel Dörfler 335675f44eSAxel Dörfler 34d3dd01a5SAxel Dörfler /* 35d3dd01a5SAxel Dörfler Note: for testing, the best way is to create a small file image, and 36d3dd01a5SAxel Dörfler register it, for example via the "diskimage" tool (mountvolume might also 37d3dd01a5SAxel Dörfler work). 38d3dd01a5SAxel Dörfler You can then create partitions on it via DriveSetup, or simply copy an 39d3dd01a5SAxel Dörfler existing drive to it, for example via: 40d3dd01a5SAxel Dörfler $ dd if=/dev/disk/ata/0/master/raw of=test.image bs=1M count=10 41d3dd01a5SAxel Dörfler 42d3dd01a5SAxel Dörfler It will automatically appear in BootManager once it is registered, and, 43d3dd01a5SAxel Dörfler depending on its parition layout, you can then install the boot menu on 44d3dd01a5SAxel Dörfler it, and directly test it via qemu. 45d3dd01a5SAxel Dörfler */ 46d3dd01a5SAxel Dörfler 47d3dd01a5SAxel Dörfler 48*546208a5SOliver Tappe #undef B_TRANSLATION_CONTEXT 49*546208a5SOliver Tappe #define B_TRANSLATION_CONTEXT "LegacyBootMenu" 505675f44eSAxel Dörfler 515675f44eSAxel Dörfler 525675f44eSAxel Dörfler struct MasterBootRecord { 535675f44eSAxel Dörfler uint8 bootLoader[440]; 545675f44eSAxel Dörfler uint8 diskSignature[4]; 555675f44eSAxel Dörfler uint8 reserved[2]; 565675f44eSAxel Dörfler uint8 partition[64]; 575675f44eSAxel Dörfler uint8 signature[2]; 585675f44eSAxel Dörfler }; 595675f44eSAxel Dörfler 605675f44eSAxel Dörfler 615675f44eSAxel Dörfler class LittleEndianMallocIO : public BMallocIO { 625675f44eSAxel Dörfler public: 635675f44eSAxel Dörfler bool WriteInt8(int8 value); 645675f44eSAxel Dörfler bool WriteInt16(int16 value); 655675f44eSAxel Dörfler bool WriteInt32(int32 value); 665675f44eSAxel Dörfler bool WriteInt64(int64 value); 675675f44eSAxel Dörfler bool WriteString(const char* value); 685675f44eSAxel Dörfler bool Align(int16 alignment); 695675f44eSAxel Dörfler bool Fill(int16 size, int8 fillByte); 705675f44eSAxel Dörfler }; 715675f44eSAxel Dörfler 725675f44eSAxel Dörfler 7349c044abSAxel Dörfler class PartitionVisitor : public BDiskDeviceVisitor { 745675f44eSAxel Dörfler public: 7549c044abSAxel Dörfler PartitionVisitor(); 765675f44eSAxel Dörfler 775675f44eSAxel Dörfler virtual bool Visit(BDiskDevice* device); 785675f44eSAxel Dörfler virtual bool Visit(BPartition* partition, int32 level); 795675f44eSAxel Dörfler 805675f44eSAxel Dörfler bool HasPartitions() const; 815675f44eSAxel Dörfler off_t FirstOffset() const; 825675f44eSAxel Dörfler 835675f44eSAxel Dörfler private: 8449c044abSAxel Dörfler off_t fFirstOffset; 8549c044abSAxel Dörfler }; 8649c044abSAxel Dörfler 8749c044abSAxel Dörfler 8849c044abSAxel Dörfler class PartitionRecorder : public BDiskDeviceVisitor { 8949c044abSAxel Dörfler public: 9049c044abSAxel Dörfler PartitionRecorder(BMessage& settings, 9149c044abSAxel Dörfler int8 biosDrive); 9249c044abSAxel Dörfler 9349c044abSAxel Dörfler virtual bool Visit(BDiskDevice* device); 9449c044abSAxel Dörfler virtual bool Visit(BPartition* partition, int32 level); 9549c044abSAxel Dörfler 9649c044abSAxel Dörfler bool FoundPartitions() const; 975675f44eSAxel Dörfler 985675f44eSAxel Dörfler private: 9949c044abSAxel Dörfler BMessage& fSettings; 10049c044abSAxel Dörfler int32 fUnnamedIndex; 10149c044abSAxel Dörfler int8 fBIOSDrive; 10249c044abSAxel Dörfler bool fFound; 1035675f44eSAxel Dörfler }; 1045675f44eSAxel Dörfler 1055675f44eSAxel Dörfler 1065675f44eSAxel Dörfler static const uint32 kBlockSize = 512; 1075675f44eSAxel Dörfler static const uint32 kNumberOfBootLoaderBlocks = 4; 1085675f44eSAxel Dörfler // The number of blocks required to store the 1095675f44eSAxel Dörfler // MBR including the Haiku boot loader. 1105675f44eSAxel Dörfler 1115675f44eSAxel Dörfler static const uint32 kMBRSignature = 0xAA55; 1125675f44eSAxel Dörfler 1135675f44eSAxel Dörfler static const int32 kMaxBootMenuItemLength = 70; 1145675f44eSAxel Dörfler 1155675f44eSAxel Dörfler 1165675f44eSAxel Dörfler bool 1175675f44eSAxel Dörfler LittleEndianMallocIO::WriteInt8(int8 value) 1185675f44eSAxel Dörfler { 1195675f44eSAxel Dörfler return Write(&value, sizeof(value)) == sizeof(value); 1205675f44eSAxel Dörfler } 1215675f44eSAxel Dörfler 1225675f44eSAxel Dörfler 1235675f44eSAxel Dörfler bool 1245675f44eSAxel Dörfler LittleEndianMallocIO::WriteInt16(int16 value) 1255675f44eSAxel Dörfler { 1265675f44eSAxel Dörfler return WriteInt8(value & 0xff) 1275675f44eSAxel Dörfler && WriteInt8(value >> 8); 1285675f44eSAxel Dörfler } 1295675f44eSAxel Dörfler 1305675f44eSAxel Dörfler 1315675f44eSAxel Dörfler bool 1325675f44eSAxel Dörfler LittleEndianMallocIO::WriteInt32(int32 value) 1335675f44eSAxel Dörfler { 1345675f44eSAxel Dörfler return WriteInt8(value & 0xff) 1355675f44eSAxel Dörfler && WriteInt8(value >> 8) 1365675f44eSAxel Dörfler && WriteInt8(value >> 16) 1375675f44eSAxel Dörfler && WriteInt8(value >> 24); 1385675f44eSAxel Dörfler } 1395675f44eSAxel Dörfler 1405675f44eSAxel Dörfler 1415675f44eSAxel Dörfler bool 1425675f44eSAxel Dörfler LittleEndianMallocIO::WriteInt64(int64 value) 1435675f44eSAxel Dörfler { 1445675f44eSAxel Dörfler return WriteInt32(value) && WriteInt32(value >> 32); 1455675f44eSAxel Dörfler } 1465675f44eSAxel Dörfler 1475675f44eSAxel Dörfler 1485675f44eSAxel Dörfler bool 1495675f44eSAxel Dörfler LittleEndianMallocIO::WriteString(const char* value) 1505675f44eSAxel Dörfler { 1515675f44eSAxel Dörfler int len = strlen(value) + 1; 1525675f44eSAxel Dörfler return WriteInt8(len) 1535675f44eSAxel Dörfler && Write(value, len) == len; 1545675f44eSAxel Dörfler } 1555675f44eSAxel Dörfler 1565675f44eSAxel Dörfler 1575675f44eSAxel Dörfler bool 1585675f44eSAxel Dörfler LittleEndianMallocIO::Align(int16 alignment) 1595675f44eSAxel Dörfler { 1605675f44eSAxel Dörfler if ((Position() % alignment) == 0) 1615675f44eSAxel Dörfler return true; 1625675f44eSAxel Dörfler return Fill(alignment - (Position() % alignment), 0); 1635675f44eSAxel Dörfler } 1645675f44eSAxel Dörfler 1655675f44eSAxel Dörfler 1665675f44eSAxel Dörfler bool 1675675f44eSAxel Dörfler LittleEndianMallocIO::Fill(int16 size, int8 fillByte) 1685675f44eSAxel Dörfler { 1695675f44eSAxel Dörfler for (int i = 0; i < size; i ++) { 1705675f44eSAxel Dörfler if (!WriteInt8(fillByte)) 1715675f44eSAxel Dörfler return false; 1725675f44eSAxel Dörfler } 1735675f44eSAxel Dörfler return true; 1745675f44eSAxel Dörfler } 1755675f44eSAxel Dörfler 1765675f44eSAxel Dörfler 1775675f44eSAxel Dörfler // #pragma mark - 1785675f44eSAxel Dörfler 1795675f44eSAxel Dörfler 18049c044abSAxel Dörfler PartitionVisitor::PartitionVisitor() 18149c044abSAxel Dörfler : 18249c044abSAxel Dörfler fFirstOffset(LONGLONG_MAX) 18349c044abSAxel Dörfler { 18449c044abSAxel Dörfler } 18549c044abSAxel Dörfler 18649c044abSAxel Dörfler 18749c044abSAxel Dörfler bool 18849c044abSAxel Dörfler PartitionVisitor::Visit(BDiskDevice* device) 18949c044abSAxel Dörfler { 19049c044abSAxel Dörfler return false; 19149c044abSAxel Dörfler } 19249c044abSAxel Dörfler 19349c044abSAxel Dörfler 19449c044abSAxel Dörfler bool 19549c044abSAxel Dörfler PartitionVisitor::Visit(BPartition* partition, int32 level) 19649c044abSAxel Dörfler { 19749c044abSAxel Dörfler if (partition->Offset() < fFirstOffset) 19849c044abSAxel Dörfler fFirstOffset = partition->Offset(); 19949c044abSAxel Dörfler 20049c044abSAxel Dörfler return false; 20149c044abSAxel Dörfler } 20249c044abSAxel Dörfler 20349c044abSAxel Dörfler 20449c044abSAxel Dörfler bool 20549c044abSAxel Dörfler PartitionVisitor::HasPartitions() const 20649c044abSAxel Dörfler { 20749c044abSAxel Dörfler return fFirstOffset != LONGLONG_MAX; 20849c044abSAxel Dörfler } 20949c044abSAxel Dörfler 21049c044abSAxel Dörfler 21149c044abSAxel Dörfler off_t 21249c044abSAxel Dörfler PartitionVisitor::FirstOffset() const 21349c044abSAxel Dörfler { 21449c044abSAxel Dörfler return fFirstOffset; 21549c044abSAxel Dörfler } 21649c044abSAxel Dörfler 21749c044abSAxel Dörfler 21849c044abSAxel Dörfler // #pragma mark - 21949c044abSAxel Dörfler 22049c044abSAxel Dörfler 22149c044abSAxel Dörfler PartitionRecorder::PartitionRecorder(BMessage& settings, int8 biosDrive) 2225675f44eSAxel Dörfler : 2235675f44eSAxel Dörfler fSettings(settings), 22449c044abSAxel Dörfler fUnnamedIndex(0), 22549c044abSAxel Dörfler fBIOSDrive(biosDrive), 22649c044abSAxel Dörfler fFound(false) 2275675f44eSAxel Dörfler { 2285675f44eSAxel Dörfler } 2295675f44eSAxel Dörfler 2305675f44eSAxel Dörfler 2315675f44eSAxel Dörfler bool 2325675f44eSAxel Dörfler PartitionRecorder::Visit(BDiskDevice* device) 2335675f44eSAxel Dörfler { 2345675f44eSAxel Dörfler return false; 2355675f44eSAxel Dörfler } 2365675f44eSAxel Dörfler 2375675f44eSAxel Dörfler 2385675f44eSAxel Dörfler bool 2395675f44eSAxel Dörfler PartitionRecorder::Visit(BPartition* partition, int32 level) 2405675f44eSAxel Dörfler { 2415675f44eSAxel Dörfler if (partition->ContainsPartitioningSystem()) 2425675f44eSAxel Dörfler return false; 2435675f44eSAxel Dörfler 2445675f44eSAxel Dörfler BPath partitionPath; 2455675f44eSAxel Dörfler partition->GetPath(&partitionPath); 2465675f44eSAxel Dörfler 2475675f44eSAxel Dörfler BString buffer; 2485675f44eSAxel Dörfler const char* name = partition->ContentName(); 2495675f44eSAxel Dörfler if (name == NULL) { 2505675f44eSAxel Dörfler BString number; 25149c044abSAxel Dörfler number << ++fUnnamedIndex; 2525675f44eSAxel Dörfler buffer << B_TRANSLATE_COMMENT("Unnamed %d", 2535675f44eSAxel Dörfler "Default name of a partition whose name could not be read from " 2545675f44eSAxel Dörfler "disk; characters in codepage 437 are allowed only"); 2555675f44eSAxel Dörfler buffer.ReplaceFirst("%d", number); 2565675f44eSAxel Dörfler name = buffer.String(); 2575675f44eSAxel Dörfler } 2585675f44eSAxel Dörfler 2595675f44eSAxel Dörfler const char* type = partition->Type(); 2605675f44eSAxel Dörfler if (type == NULL) 2615675f44eSAxel Dörfler type = B_TRANSLATE_COMMENT("Unknown", "Text is shown for an unknown " 2625675f44eSAxel Dörfler "partition type"); 2635675f44eSAxel Dörfler 2645675f44eSAxel Dörfler BMessage message; 2655675f44eSAxel Dörfler // Data as required by BootLoader.h 2665675f44eSAxel Dörfler message.AddBool("show", true); 2675675f44eSAxel Dörfler message.AddString("name", name); 2685675f44eSAxel Dörfler message.AddString("type", type); 2695675f44eSAxel Dörfler message.AddString("path", partitionPath.Path()); 27049c044abSAxel Dörfler if (fBIOSDrive != 0) 27149c044abSAxel Dörfler message.AddInt8("drive", fBIOSDrive); 2725675f44eSAxel Dörfler message.AddInt64("size", partition->Size()); 27349c044abSAxel Dörfler message.AddInt64("offset", partition->Offset()); 2745675f44eSAxel Dörfler 27549c044abSAxel Dörfler fSettings.AddMessage("partition", &message); 27649c044abSAxel Dörfler fFound = true; 2775675f44eSAxel Dörfler 2785675f44eSAxel Dörfler return false; 2795675f44eSAxel Dörfler } 2805675f44eSAxel Dörfler 2815675f44eSAxel Dörfler 28249c044abSAxel Dörfler bool 28349c044abSAxel Dörfler PartitionRecorder::FoundPartitions() const 28449c044abSAxel Dörfler { 28549c044abSAxel Dörfler return fFound; 28649c044abSAxel Dörfler } 28749c044abSAxel Dörfler 28849c044abSAxel Dörfler 2895675f44eSAxel Dörfler // #pragma mark - 2905675f44eSAxel Dörfler 2915675f44eSAxel Dörfler 2925675f44eSAxel Dörfler LegacyBootMenu::LegacyBootMenu() 2935675f44eSAxel Dörfler { 2945675f44eSAxel Dörfler } 2955675f44eSAxel Dörfler 2965675f44eSAxel Dörfler 2975675f44eSAxel Dörfler LegacyBootMenu::~LegacyBootMenu() 2985675f44eSAxel Dörfler { 2995675f44eSAxel Dörfler } 3005675f44eSAxel Dörfler 3015675f44eSAxel Dörfler 3025675f44eSAxel Dörfler bool 30349c044abSAxel Dörfler LegacyBootMenu::IsInstalled(const BootDrive& drive) 3045675f44eSAxel Dörfler { 30549c044abSAxel Dörfler // TODO: detect bootman 3065675f44eSAxel Dörfler return false; 3075675f44eSAxel Dörfler } 3085675f44eSAxel Dörfler 3095675f44eSAxel Dörfler 3105675f44eSAxel Dörfler status_t 31149c044abSAxel Dörfler LegacyBootMenu::CanBeInstalled(const BootDrive& drive) 31249c044abSAxel Dörfler { 31349c044abSAxel Dörfler BDiskDevice device; 31449c044abSAxel Dörfler status_t status = drive.GetDiskDevice(device); 31549c044abSAxel Dörfler if (status != B_OK) 31649c044abSAxel Dörfler return status; 31749c044abSAxel Dörfler 31849c044abSAxel Dörfler PartitionVisitor visitor; 31949c044abSAxel Dörfler device.VisitEachDescendant(&visitor); 32049c044abSAxel Dörfler 32149c044abSAxel Dörfler // Enough space to write boot menu to drive? 32249c044abSAxel Dörfler if (!visitor.HasPartitions() || visitor.FirstOffset() < sizeof(kBootLoader)) 32349c044abSAxel Dörfler return B_PARTITION_TOO_SMALL; 32449c044abSAxel Dörfler 32549c044abSAxel Dörfler return B_OK; 32649c044abSAxel Dörfler } 32749c044abSAxel Dörfler 32849c044abSAxel Dörfler 32949c044abSAxel Dörfler status_t 33049c044abSAxel Dörfler LegacyBootMenu::CollectPartitions(const BootDrive& drive, BMessage& settings) 3315675f44eSAxel Dörfler { 3325675f44eSAxel Dörfler status_t status = B_ERROR; 3335675f44eSAxel Dörfler 33449c044abSAxel Dörfler // Remove previous partitions, if any 33549c044abSAxel Dörfler settings.RemoveName("partition"); 33649c044abSAxel Dörfler 3375675f44eSAxel Dörfler BDiskDeviceRoster diskDeviceRoster; 3385675f44eSAxel Dörfler BDiskDevice device; 33949c044abSAxel Dörfler bool partitionsFound = false; 34049c044abSAxel Dörfler 3415675f44eSAxel Dörfler while (diskDeviceRoster.GetNextDevice(&device) == B_OK) { 3425675f44eSAxel Dörfler BPath path; 3435675f44eSAxel Dörfler status_t status = device.GetPath(&path); 3445675f44eSAxel Dörfler if (status != B_OK) 3455675f44eSAxel Dörfler continue; 3465675f44eSAxel Dörfler 34749c044abSAxel Dörfler // Skip not from BIOS bootable drives that are not the target disk 34849c044abSAxel Dörfler int8 biosDrive = 0; 34949c044abSAxel Dörfler if (path != drive.Path() 35049c044abSAxel Dörfler && _GetBIOSDrive(path.Path(), biosDrive) != B_OK) 3515675f44eSAxel Dörfler continue; 3525675f44eSAxel Dörfler 35349c044abSAxel Dörfler PartitionRecorder recorder(settings, biosDrive); 3545675f44eSAxel Dörfler device.VisitEachDescendant(&recorder); 3555675f44eSAxel Dörfler 35649c044abSAxel Dörfler partitionsFound |= recorder.FoundPartitions(); 3575675f44eSAxel Dörfler } 3585675f44eSAxel Dörfler 35949c044abSAxel Dörfler return partitionsFound ? B_OK : status; 3605675f44eSAxel Dörfler } 3615675f44eSAxel Dörfler 3625675f44eSAxel Dörfler 3635675f44eSAxel Dörfler status_t 36449c044abSAxel Dörfler LegacyBootMenu::Install(const BootDrive& drive, BMessage& settings) 3655675f44eSAxel Dörfler { 3665675f44eSAxel Dörfler int32 defaultPartitionIndex; 36749c044abSAxel Dörfler if (settings.FindInt32("defaultPartition", &defaultPartitionIndex) != B_OK) 3685675f44eSAxel Dörfler return B_BAD_VALUE; 3695675f44eSAxel Dörfler 3705675f44eSAxel Dörfler int32 timeout; 37149c044abSAxel Dörfler if (settings.FindInt32("timeout", &timeout) != B_OK) 3725675f44eSAxel Dörfler return B_BAD_VALUE; 3735675f44eSAxel Dörfler 37449c044abSAxel Dörfler int fd = open(drive.Path(), O_RDWR); 3755675f44eSAxel Dörfler if (fd < 0) 3765675f44eSAxel Dörfler return B_IO_ERROR; 3775675f44eSAxel Dörfler 3785675f44eSAxel Dörfler MasterBootRecord oldMBR; 3795675f44eSAxel Dörfler if (read(fd, &oldMBR, sizeof(oldMBR)) != sizeof(oldMBR)) { 3805675f44eSAxel Dörfler close(fd); 3815675f44eSAxel Dörfler return B_IO_ERROR; 3825675f44eSAxel Dörfler } 3835675f44eSAxel Dörfler 3845675f44eSAxel Dörfler if (!_IsValid(&oldMBR)) { 3855675f44eSAxel Dörfler close(fd); 3865675f44eSAxel Dörfler return B_BAD_VALUE; 3875675f44eSAxel Dörfler } 3885675f44eSAxel Dörfler 3895675f44eSAxel Dörfler LittleEndianMallocIO newBootLoader; 3905675f44eSAxel Dörfler ssize_t size = sizeof(kBootLoader); 3915675f44eSAxel Dörfler if (newBootLoader.Write(kBootLoader, size) != size) { 3925675f44eSAxel Dörfler close(fd); 3935675f44eSAxel Dörfler return B_NO_MEMORY; 3945675f44eSAxel Dörfler } 3955675f44eSAxel Dörfler 3965675f44eSAxel Dörfler MasterBootRecord* newMBR = (MasterBootRecord*)newBootLoader.Buffer(); 3975675f44eSAxel Dörfler _CopyPartitionTable(newMBR, &oldMBR); 3985675f44eSAxel Dörfler 3995675f44eSAxel Dörfler int menuEntries = 0; 4005675f44eSAxel Dörfler int defaultMenuEntry = 0; 4015675f44eSAxel Dörfler BMessage partition; 4025675f44eSAxel Dörfler int32 index; 40349c044abSAxel Dörfler for (index = 0; settings.FindMessage("partition", index, 4045675f44eSAxel Dörfler &partition) == B_OK; index ++) { 4055675f44eSAxel Dörfler bool show; 4065675f44eSAxel Dörfler partition.FindBool("show", &show); 4075675f44eSAxel Dörfler if (!show) 4085675f44eSAxel Dörfler continue; 4095675f44eSAxel Dörfler if (index == defaultPartitionIndex) 4105675f44eSAxel Dörfler defaultMenuEntry = menuEntries; 4115675f44eSAxel Dörfler 4125675f44eSAxel Dörfler menuEntries ++; 4135675f44eSAxel Dörfler } 4145675f44eSAxel Dörfler newBootLoader.WriteInt16(menuEntries); 4155675f44eSAxel Dörfler newBootLoader.WriteInt16(defaultMenuEntry); 4165675f44eSAxel Dörfler newBootLoader.WriteInt16(timeout); 4175675f44eSAxel Dörfler 41849c044abSAxel Dörfler for (index = 0; settings.FindMessage("partition", index, 4195675f44eSAxel Dörfler &partition) == B_OK; index ++) { 4205675f44eSAxel Dörfler bool show; 4215675f44eSAxel Dörfler BString name; 4225675f44eSAxel Dörfler BString path; 4235675f44eSAxel Dörfler int64 offset; 4245675f44eSAxel Dörfler int8 drive; 4255675f44eSAxel Dörfler partition.FindBool("show", &show); 4265675f44eSAxel Dörfler partition.FindString("name", &name); 4275675f44eSAxel Dörfler partition.FindString("path", &path); 4285675f44eSAxel Dörfler // LegacyBootMenu specific data 4295675f44eSAxel Dörfler partition.FindInt64("offset", &offset); 4305675f44eSAxel Dörfler partition.FindInt8("drive", &drive); 4315675f44eSAxel Dörfler if (!show) 4325675f44eSAxel Dörfler continue; 4335675f44eSAxel Dörfler 4345675f44eSAxel Dörfler BString biosName; 4355675f44eSAxel Dörfler _ConvertToBIOSText(name.String(), biosName); 4365675f44eSAxel Dörfler 4375675f44eSAxel Dörfler newBootLoader.WriteString(biosName.String()); 4385675f44eSAxel Dörfler newBootLoader.WriteInt8(drive); 4395675f44eSAxel Dörfler newBootLoader.WriteInt64(offset / kBlockSize); 4405675f44eSAxel Dörfler } 4415675f44eSAxel Dörfler 4425675f44eSAxel Dörfler if (!newBootLoader.Align(kBlockSize)) { 4435675f44eSAxel Dörfler close(fd); 4445675f44eSAxel Dörfler return B_ERROR; 4455675f44eSAxel Dörfler } 4465675f44eSAxel Dörfler 4475675f44eSAxel Dörfler lseek(fd, 0, SEEK_SET); 4485675f44eSAxel Dörfler const uint8* buffer = (const uint8*)newBootLoader.Buffer(); 4495675f44eSAxel Dörfler status_t status = _WriteBlocks(fd, buffer, newBootLoader.Position()); 4505675f44eSAxel Dörfler close(fd); 4515675f44eSAxel Dörfler return status; 4525675f44eSAxel Dörfler } 4535675f44eSAxel Dörfler 4545675f44eSAxel Dörfler 4555675f44eSAxel Dörfler status_t 4565675f44eSAxel Dörfler LegacyBootMenu::SaveMasterBootRecord(BMessage* settings, BFile* file) 4575675f44eSAxel Dörfler { 4585675f44eSAxel Dörfler BString path; 4595675f44eSAxel Dörfler 4605675f44eSAxel Dörfler if (settings->FindString("disk", &path) != B_OK) 4615675f44eSAxel Dörfler return B_BAD_VALUE; 4625675f44eSAxel Dörfler 4635675f44eSAxel Dörfler int fd = open(path.String(), O_RDONLY); 4645675f44eSAxel Dörfler if (fd < 0) 4655675f44eSAxel Dörfler return B_IO_ERROR; 4665675f44eSAxel Dörfler 4675675f44eSAxel Dörfler ssize_t size = kBlockSize * kNumberOfBootLoaderBlocks; 4685675f44eSAxel Dörfler uint8* buffer = new(std::nothrow) uint8[size]; 4695675f44eSAxel Dörfler if (buffer == NULL) { 4705675f44eSAxel Dörfler close(fd); 4715675f44eSAxel Dörfler return B_NO_MEMORY; 4725675f44eSAxel Dörfler } 4735675f44eSAxel Dörfler 4745675f44eSAxel Dörfler status_t status = _ReadBlocks(fd, buffer, size); 4755675f44eSAxel Dörfler if (status != B_OK) { 4765675f44eSAxel Dörfler close(fd); 4775675f44eSAxel Dörfler delete[] buffer; 4785675f44eSAxel Dörfler return B_IO_ERROR; 4795675f44eSAxel Dörfler } 4805675f44eSAxel Dörfler 4815675f44eSAxel Dörfler MasterBootRecord* mbr = (MasterBootRecord*)buffer; 4825675f44eSAxel Dörfler if (!_IsValid(mbr)) { 4835675f44eSAxel Dörfler close(fd); 4845675f44eSAxel Dörfler delete[] buffer; 4855675f44eSAxel Dörfler return B_BAD_VALUE; 4865675f44eSAxel Dörfler } 4875675f44eSAxel Dörfler 4885675f44eSAxel Dörfler if (file->Write(buffer, size) != size) 4895675f44eSAxel Dörfler status = B_IO_ERROR; 4905675f44eSAxel Dörfler delete[] buffer; 4915675f44eSAxel Dörfler close(fd); 4925675f44eSAxel Dörfler return status; 4935675f44eSAxel Dörfler } 4945675f44eSAxel Dörfler 4955675f44eSAxel Dörfler 4965675f44eSAxel Dörfler status_t 4975675f44eSAxel Dörfler LegacyBootMenu::RestoreMasterBootRecord(BMessage* settings, BFile* file) 4985675f44eSAxel Dörfler { 4995675f44eSAxel Dörfler BString path; 5005675f44eSAxel Dörfler if (settings->FindString("disk", &path) != B_OK) 5015675f44eSAxel Dörfler return B_BAD_VALUE; 5025675f44eSAxel Dörfler 5035675f44eSAxel Dörfler int fd = open(path.String(), O_RDWR); 5045675f44eSAxel Dörfler if (fd < 0) 5055675f44eSAxel Dörfler return B_IO_ERROR; 5065675f44eSAxel Dörfler 5075675f44eSAxel Dörfler MasterBootRecord oldMBR; 5085675f44eSAxel Dörfler if (read(fd, &oldMBR, sizeof(oldMBR)) != sizeof(oldMBR)) { 5095675f44eSAxel Dörfler close(fd); 5105675f44eSAxel Dörfler return B_IO_ERROR; 5115675f44eSAxel Dörfler } 5125675f44eSAxel Dörfler if (!_IsValid(&oldMBR)) { 5135675f44eSAxel Dörfler close(fd); 5145675f44eSAxel Dörfler return B_BAD_VALUE; 5155675f44eSAxel Dörfler } 5165675f44eSAxel Dörfler 5175675f44eSAxel Dörfler lseek(fd, 0, SEEK_SET); 5185675f44eSAxel Dörfler 5195675f44eSAxel Dörfler size_t size = kBlockSize * kNumberOfBootLoaderBlocks; 5205675f44eSAxel Dörfler uint8* buffer = new(std::nothrow) uint8[size]; 5215675f44eSAxel Dörfler if (buffer == NULL) { 5225675f44eSAxel Dörfler close(fd); 5235675f44eSAxel Dörfler return B_NO_MEMORY; 5245675f44eSAxel Dörfler } 5255675f44eSAxel Dörfler 5265675f44eSAxel Dörfler if (file->Read(buffer, size) != (ssize_t)size) { 5275675f44eSAxel Dörfler close(fd); 5285675f44eSAxel Dörfler delete[] buffer; 5295675f44eSAxel Dörfler return B_IO_ERROR; 5305675f44eSAxel Dörfler } 5315675f44eSAxel Dörfler 5325675f44eSAxel Dörfler MasterBootRecord* newMBR = (MasterBootRecord*)buffer; 5335675f44eSAxel Dörfler if (!_IsValid(newMBR)) { 5345675f44eSAxel Dörfler close(fd); 5355675f44eSAxel Dörfler delete[] buffer; 5365675f44eSAxel Dörfler return B_BAD_VALUE; 5375675f44eSAxel Dörfler } 5385675f44eSAxel Dörfler 5395675f44eSAxel Dörfler _CopyPartitionTable(newMBR, &oldMBR); 5405675f44eSAxel Dörfler 5415675f44eSAxel Dörfler status_t status = _WriteBlocks(fd, buffer, size); 5425675f44eSAxel Dörfler delete[] buffer; 5435675f44eSAxel Dörfler close(fd); 5445675f44eSAxel Dörfler return status; 5455675f44eSAxel Dörfler } 5465675f44eSAxel Dörfler 5475675f44eSAxel Dörfler 5485675f44eSAxel Dörfler status_t 5495675f44eSAxel Dörfler LegacyBootMenu::GetDisplayText(const char* text, BString& displayText) 5505675f44eSAxel Dörfler { 5515675f44eSAxel Dörfler BString biosText; 5525675f44eSAxel Dörfler if (!_ConvertToBIOSText(text, biosText)) { 5535675f44eSAxel Dörfler displayText = "???"; 5545675f44eSAxel Dörfler return B_ERROR; 5555675f44eSAxel Dörfler } 5565675f44eSAxel Dörfler 5575675f44eSAxel Dörfler // convert back to UTF-8 5585675f44eSAxel Dörfler int32 biosTextLength = biosText.Length(); 5595675f44eSAxel Dörfler int32 bufferLength = strlen(text); 5605675f44eSAxel Dörfler char* buffer = displayText.LockBuffer(bufferLength + 1); 5615675f44eSAxel Dörfler int32 state = 0; 5625675f44eSAxel Dörfler if (convert_to_utf8(B_MS_DOS_CONVERSION, 5635675f44eSAxel Dörfler biosText.String(), &biosTextLength, 5645675f44eSAxel Dörfler buffer, &bufferLength, &state) != B_OK) { 5655675f44eSAxel Dörfler displayText.UnlockBuffer(0); 5665675f44eSAxel Dörfler displayText = "???"; 5675675f44eSAxel Dörfler return B_ERROR; 5685675f44eSAxel Dörfler } 5695675f44eSAxel Dörfler 5705675f44eSAxel Dörfler buffer[bufferLength] = '\0'; 5715675f44eSAxel Dörfler displayText.UnlockBuffer(bufferLength); 5725675f44eSAxel Dörfler return B_OK; 5735675f44eSAxel Dörfler } 5745675f44eSAxel Dörfler 5755675f44eSAxel Dörfler 5765675f44eSAxel Dörfler bool 5775675f44eSAxel Dörfler LegacyBootMenu::_ConvertToBIOSText(const char* text, BString& biosText) 5785675f44eSAxel Dörfler { 5795675f44eSAxel Dörfler // convert text in UTF-8 to 'code page 437' 5805675f44eSAxel Dörfler int32 textLength = strlen(text); 5815675f44eSAxel Dörfler 5825675f44eSAxel Dörfler int32 biosTextLength = textLength; 5835675f44eSAxel Dörfler char* buffer = biosText.LockBuffer(biosTextLength + 1); 5845675f44eSAxel Dörfler if (buffer == NULL) { 5855675f44eSAxel Dörfler biosText.UnlockBuffer(0); 5865675f44eSAxel Dörfler return false; 5875675f44eSAxel Dörfler } 5885675f44eSAxel Dörfler 5895675f44eSAxel Dörfler int32 state = 0; 5905675f44eSAxel Dörfler if (convert_from_utf8(B_MS_DOS_CONVERSION, text, &textLength, 5915675f44eSAxel Dörfler buffer, &biosTextLength, &state) != B_OK) { 5925675f44eSAxel Dörfler biosText.UnlockBuffer(0); 5935675f44eSAxel Dörfler return false; 5945675f44eSAxel Dörfler } 5955675f44eSAxel Dörfler 5965675f44eSAxel Dörfler buffer[biosTextLength] = '\0'; 5975675f44eSAxel Dörfler biosText.UnlockBuffer(biosTextLength); 5985675f44eSAxel Dörfler return biosTextLength < kMaxBootMenuItemLength; 5995675f44eSAxel Dörfler } 6005675f44eSAxel Dörfler 6015675f44eSAxel Dörfler 60249c044abSAxel Dörfler status_t 60349c044abSAxel Dörfler LegacyBootMenu::_GetBIOSDrive(const char* device, int8& drive) 6045675f44eSAxel Dörfler { 6055675f44eSAxel Dörfler int fd = open(device, O_RDONLY); 6065675f44eSAxel Dörfler if (fd < 0) 60749c044abSAxel Dörfler return errno; 60849c044abSAxel Dörfler 60949c044abSAxel Dörfler status_t status = ioctl(fd, B_GET_BIOS_DRIVE_ID, drive, 1); 6105675f44eSAxel Dörfler close(fd); 61149c044abSAxel Dörfler return status; 6125675f44eSAxel Dörfler } 6135675f44eSAxel Dörfler 6145675f44eSAxel Dörfler 6155675f44eSAxel Dörfler status_t 6165675f44eSAxel Dörfler LegacyBootMenu::_ReadBlocks(int fd, uint8* buffer, size_t size) 6175675f44eSAxel Dörfler { 6185675f44eSAxel Dörfler if (size % kBlockSize != 0) { 6195675f44eSAxel Dörfler fprintf(stderr, "_ReadBlocks buffer size must be a multiple of %d\n", 6205675f44eSAxel Dörfler (int)kBlockSize); 6215675f44eSAxel Dörfler return B_BAD_VALUE; 6225675f44eSAxel Dörfler } 6235675f44eSAxel Dörfler const size_t blocks = size / kBlockSize; 6245675f44eSAxel Dörfler uint8* block = buffer; 6255675f44eSAxel Dörfler for (size_t i = 0; i < blocks; i ++, block += kBlockSize) { 6265675f44eSAxel Dörfler if (read(fd, block, kBlockSize) != (ssize_t)kBlockSize) 6275675f44eSAxel Dörfler return B_IO_ERROR; 6285675f44eSAxel Dörfler } 6295675f44eSAxel Dörfler return B_OK; 6305675f44eSAxel Dörfler } 6315675f44eSAxel Dörfler 6325675f44eSAxel Dörfler 6335675f44eSAxel Dörfler status_t 6345675f44eSAxel Dörfler LegacyBootMenu::_WriteBlocks(int fd, const uint8* buffer, size_t size) 6355675f44eSAxel Dörfler { 6365675f44eSAxel Dörfler if (size % kBlockSize != 0) { 6375675f44eSAxel Dörfler fprintf(stderr, "_WriteBlocks buffer size must be a multiple of %d\n", 6385675f44eSAxel Dörfler (int)kBlockSize); 6395675f44eSAxel Dörfler return B_BAD_VALUE; 6405675f44eSAxel Dörfler } 6415675f44eSAxel Dörfler const size_t blocks = size / kBlockSize; 6425675f44eSAxel Dörfler const uint8* block = buffer; 6435675f44eSAxel Dörfler for (size_t i = 0; i < blocks; i ++, block += kBlockSize) { 6445675f44eSAxel Dörfler if (write(fd, block, kBlockSize) != (ssize_t)kBlockSize) 6455675f44eSAxel Dörfler return B_IO_ERROR; 6465675f44eSAxel Dörfler } 6475675f44eSAxel Dörfler return B_OK; 6485675f44eSAxel Dörfler } 6495675f44eSAxel Dörfler 6505675f44eSAxel Dörfler 6515675f44eSAxel Dörfler void 6525675f44eSAxel Dörfler LegacyBootMenu::_CopyPartitionTable(MasterBootRecord* destination, 6535675f44eSAxel Dörfler const MasterBootRecord* source) 6545675f44eSAxel Dörfler { 6555675f44eSAxel Dörfler memcpy(destination->diskSignature, source->diskSignature, 6565675f44eSAxel Dörfler sizeof(source->diskSignature) + sizeof(source->reserved) 6575675f44eSAxel Dörfler + sizeof(source->partition)); 6585675f44eSAxel Dörfler } 6595675f44eSAxel Dörfler 6605675f44eSAxel Dörfler 6615675f44eSAxel Dörfler bool 6625675f44eSAxel Dörfler LegacyBootMenu::_IsValid(const MasterBootRecord* mbr) 6635675f44eSAxel Dörfler { 6645675f44eSAxel Dörfler return mbr->signature[0] == (kMBRSignature & 0xff) 6655675f44eSAxel Dörfler && mbr->signature[1] == (kMBRSignature >> 8); 6665675f44eSAxel Dörfler } 667