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 34*d3dd01a5SAxel Dörfler /* 35*d3dd01a5SAxel Dörfler Note: for testing, the best way is to create a small file image, and 36*d3dd01a5SAxel Dörfler register it, for example via the "diskimage" tool (mountvolume might also 37*d3dd01a5SAxel Dörfler work). 38*d3dd01a5SAxel Dörfler You can then create partitions on it via DriveSetup, or simply copy an 39*d3dd01a5SAxel Dörfler existing drive to it, for example via: 40*d3dd01a5SAxel Dörfler $ dd if=/dev/disk/ata/0/master/raw of=test.image bs=1M count=10 41*d3dd01a5SAxel Dörfler 42*d3dd01a5SAxel Dörfler It will automatically appear in BootManager once it is registered, and, 43*d3dd01a5SAxel Dörfler depending on its parition layout, you can then install the boot menu on 44*d3dd01a5SAxel Dörfler it, and directly test it via qemu. 45*d3dd01a5SAxel Dörfler */ 46*d3dd01a5SAxel Dörfler 47*d3dd01a5SAxel Dörfler 485675f44eSAxel Dörfler #undef B_TRANSLATE_CONTEXT 495675f44eSAxel Dörfler #define B_TRANSLATE_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