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>
2139681c5cSAugustin Cavalier #include <DiskDeviceTypes.h>
225675f44eSAxel Dörfler #include <DiskDeviceRoster.h>
235675f44eSAxel Dörfler #include <DiskDeviceVisitor.h>
2449c044abSAxel Dörfler #include <Drivers.h>
255675f44eSAxel Dörfler #include <File.h>
265675f44eSAxel Dörfler #include <Partition.h>
275675f44eSAxel Dörfler #include <Path.h>
285675f44eSAxel Dörfler #include <String.h>
295675f44eSAxel Dörfler #include <UTF8.h>
305675f44eSAxel Dörfler
3149c044abSAxel Dörfler #include "BootDrive.h"
325675f44eSAxel Dörfler #include "BootLoader.h"
335675f44eSAxel Dörfler
345675f44eSAxel Dörfler
35d3dd01a5SAxel Dörfler /*
36d3dd01a5SAxel Dörfler Note: for testing, the best way is to create a small file image, and
37d3dd01a5SAxel Dörfler register it, for example via the "diskimage" tool (mountvolume might also
38d3dd01a5SAxel Dörfler work).
39d3dd01a5SAxel Dörfler You can then create partitions on it via DriveSetup, or simply copy an
40d3dd01a5SAxel Dörfler existing drive to it, for example via:
41d3dd01a5SAxel Dörfler $ dd if=/dev/disk/ata/0/master/raw of=test.image bs=1M count=10
42d3dd01a5SAxel Dörfler
43d3dd01a5SAxel Dörfler It will automatically appear in BootManager once it is registered, and,
44d3dd01a5SAxel Dörfler depending on its parition layout, you can then install the boot menu on
45d3dd01a5SAxel Dörfler it, and directly test it via qemu.
46d3dd01a5SAxel Dörfler */
47d3dd01a5SAxel Dörfler
48d3dd01a5SAxel Dörfler
49546208a5SOliver Tappe #undef B_TRANSLATION_CONTEXT
50546208a5SOliver Tappe #define B_TRANSLATION_CONTEXT "LegacyBootMenu"
515675f44eSAxel Dörfler
525675f44eSAxel Dörfler
535675f44eSAxel Dörfler struct MasterBootRecord {
545675f44eSAxel Dörfler uint8 bootLoader[440];
555675f44eSAxel Dörfler uint8 diskSignature[4];
565675f44eSAxel Dörfler uint8 reserved[2];
575675f44eSAxel Dörfler uint8 partition[64];
585675f44eSAxel Dörfler uint8 signature[2];
595675f44eSAxel Dörfler };
605675f44eSAxel Dörfler
615675f44eSAxel Dörfler
625675f44eSAxel Dörfler class LittleEndianMallocIO : public BMallocIO {
635675f44eSAxel Dörfler public:
645675f44eSAxel Dörfler bool WriteInt8(int8 value);
655675f44eSAxel Dörfler bool WriteInt16(int16 value);
665675f44eSAxel Dörfler bool WriteInt32(int32 value);
675675f44eSAxel Dörfler bool WriteInt64(int64 value);
685675f44eSAxel Dörfler bool WriteString(const char* value);
695675f44eSAxel Dörfler bool Align(int16 alignment);
705675f44eSAxel Dörfler bool Fill(int16 size, int8 fillByte);
715675f44eSAxel Dörfler };
725675f44eSAxel Dörfler
735675f44eSAxel Dörfler
7449c044abSAxel Dörfler class PartitionVisitor : public BDiskDeviceVisitor {
755675f44eSAxel Dörfler public:
7649c044abSAxel Dörfler PartitionVisitor();
775675f44eSAxel Dörfler
785675f44eSAxel Dörfler virtual bool Visit(BDiskDevice* device);
795675f44eSAxel Dörfler virtual bool Visit(BPartition* partition, int32 level);
805675f44eSAxel Dörfler
815675f44eSAxel Dörfler bool HasPartitions() const;
825675f44eSAxel Dörfler off_t FirstOffset() const;
835675f44eSAxel Dörfler
845675f44eSAxel Dörfler private:
8549c044abSAxel Dörfler off_t fFirstOffset;
8649c044abSAxel Dörfler };
8749c044abSAxel Dörfler
8849c044abSAxel Dörfler
8949c044abSAxel Dörfler class PartitionRecorder : public BDiskDeviceVisitor {
9049c044abSAxel Dörfler public:
9149c044abSAxel Dörfler PartitionRecorder(BMessage& settings,
9249c044abSAxel Dörfler int8 biosDrive);
9349c044abSAxel Dörfler
9449c044abSAxel Dörfler virtual bool Visit(BDiskDevice* device);
9549c044abSAxel Dörfler virtual bool Visit(BPartition* partition, int32 level);
9649c044abSAxel Dörfler
9749c044abSAxel Dörfler bool FoundPartitions() const;
985675f44eSAxel Dörfler
995675f44eSAxel Dörfler private:
10049c044abSAxel Dörfler BMessage& fSettings;
10149c044abSAxel Dörfler int32 fUnnamedIndex;
10249c044abSAxel Dörfler int8 fBIOSDrive;
10349c044abSAxel Dörfler bool fFound;
1045675f44eSAxel Dörfler };
1055675f44eSAxel Dörfler
1065675f44eSAxel Dörfler
1075675f44eSAxel Dörfler static const uint32 kBlockSize = 512;
1085675f44eSAxel Dörfler static const uint32 kNumberOfBootLoaderBlocks = 4;
1095675f44eSAxel Dörfler // The number of blocks required to store the
1105675f44eSAxel Dörfler // MBR including the Haiku boot loader.
1115675f44eSAxel Dörfler
1125675f44eSAxel Dörfler static const uint32 kMBRSignature = 0xAA55;
1135675f44eSAxel Dörfler
1145675f44eSAxel Dörfler static const int32 kMaxBootMenuItemLength = 70;
1155675f44eSAxel Dörfler
1165675f44eSAxel Dörfler
1175675f44eSAxel Dörfler bool
WriteInt8(int8 value)1185675f44eSAxel Dörfler LittleEndianMallocIO::WriteInt8(int8 value)
1195675f44eSAxel Dörfler {
1205675f44eSAxel Dörfler return Write(&value, sizeof(value)) == sizeof(value);
1215675f44eSAxel Dörfler }
1225675f44eSAxel Dörfler
1235675f44eSAxel Dörfler
1245675f44eSAxel Dörfler bool
WriteInt16(int16 value)1255675f44eSAxel Dörfler LittleEndianMallocIO::WriteInt16(int16 value)
1265675f44eSAxel Dörfler {
1275675f44eSAxel Dörfler return WriteInt8(value & 0xff)
1285675f44eSAxel Dörfler && WriteInt8(value >> 8);
1295675f44eSAxel Dörfler }
1305675f44eSAxel Dörfler
1315675f44eSAxel Dörfler
1325675f44eSAxel Dörfler bool
WriteInt32(int32 value)1335675f44eSAxel Dörfler LittleEndianMallocIO::WriteInt32(int32 value)
1345675f44eSAxel Dörfler {
1355675f44eSAxel Dörfler return WriteInt8(value & 0xff)
1365675f44eSAxel Dörfler && WriteInt8(value >> 8)
1375675f44eSAxel Dörfler && WriteInt8(value >> 16)
1385675f44eSAxel Dörfler && WriteInt8(value >> 24);
1395675f44eSAxel Dörfler }
1405675f44eSAxel Dörfler
1415675f44eSAxel Dörfler
1425675f44eSAxel Dörfler bool
WriteInt64(int64 value)1435675f44eSAxel Dörfler LittleEndianMallocIO::WriteInt64(int64 value)
1445675f44eSAxel Dörfler {
1455675f44eSAxel Dörfler return WriteInt32(value) && WriteInt32(value >> 32);
1465675f44eSAxel Dörfler }
1475675f44eSAxel Dörfler
1485675f44eSAxel Dörfler
1495675f44eSAxel Dörfler bool
WriteString(const char * value)1505675f44eSAxel Dörfler LittleEndianMallocIO::WriteString(const char* value)
1515675f44eSAxel Dörfler {
1525675f44eSAxel Dörfler int len = strlen(value) + 1;
1535675f44eSAxel Dörfler return WriteInt8(len)
1545675f44eSAxel Dörfler && Write(value, len) == len;
1555675f44eSAxel Dörfler }
1565675f44eSAxel Dörfler
1575675f44eSAxel Dörfler
1585675f44eSAxel Dörfler bool
Align(int16 alignment)1595675f44eSAxel Dörfler LittleEndianMallocIO::Align(int16 alignment)
1605675f44eSAxel Dörfler {
1615675f44eSAxel Dörfler if ((Position() % alignment) == 0)
1625675f44eSAxel Dörfler return true;
1635675f44eSAxel Dörfler return Fill(alignment - (Position() % alignment), 0);
1645675f44eSAxel Dörfler }
1655675f44eSAxel Dörfler
1665675f44eSAxel Dörfler
1675675f44eSAxel Dörfler bool
Fill(int16 size,int8 fillByte)1685675f44eSAxel Dörfler LittleEndianMallocIO::Fill(int16 size, int8 fillByte)
1695675f44eSAxel Dörfler {
1705675f44eSAxel Dörfler for (int i = 0; i < size; i ++) {
1715675f44eSAxel Dörfler if (!WriteInt8(fillByte))
1725675f44eSAxel Dörfler return false;
1735675f44eSAxel Dörfler }
1745675f44eSAxel Dörfler return true;
1755675f44eSAxel Dörfler }
1765675f44eSAxel Dörfler
1775675f44eSAxel Dörfler
1785675f44eSAxel Dörfler // #pragma mark -
1795675f44eSAxel Dörfler
1805675f44eSAxel Dörfler
PartitionVisitor()18149c044abSAxel Dörfler PartitionVisitor::PartitionVisitor()
18249c044abSAxel Dörfler :
18349c044abSAxel Dörfler fFirstOffset(LONGLONG_MAX)
18449c044abSAxel Dörfler {
18549c044abSAxel Dörfler }
18649c044abSAxel Dörfler
18749c044abSAxel Dörfler
18849c044abSAxel Dörfler bool
Visit(BDiskDevice * device)18949c044abSAxel Dörfler PartitionVisitor::Visit(BDiskDevice* device)
19049c044abSAxel Dörfler {
19149c044abSAxel Dörfler return false;
19249c044abSAxel Dörfler }
19349c044abSAxel Dörfler
19449c044abSAxel Dörfler
19549c044abSAxel Dörfler bool
Visit(BPartition * partition,int32 level)19649c044abSAxel Dörfler PartitionVisitor::Visit(BPartition* partition, int32 level)
19749c044abSAxel Dörfler {
19849c044abSAxel Dörfler if (partition->Offset() < fFirstOffset)
19949c044abSAxel Dörfler fFirstOffset = partition->Offset();
20049c044abSAxel Dörfler
20149c044abSAxel Dörfler return false;
20249c044abSAxel Dörfler }
20349c044abSAxel Dörfler
20449c044abSAxel Dörfler
20549c044abSAxel Dörfler bool
HasPartitions() const20649c044abSAxel Dörfler PartitionVisitor::HasPartitions() const
20749c044abSAxel Dörfler {
20849c044abSAxel Dörfler return fFirstOffset != LONGLONG_MAX;
20949c044abSAxel Dörfler }
21049c044abSAxel Dörfler
21149c044abSAxel Dörfler
21249c044abSAxel Dörfler off_t
FirstOffset() const21349c044abSAxel Dörfler PartitionVisitor::FirstOffset() const
21449c044abSAxel Dörfler {
21549c044abSAxel Dörfler return fFirstOffset;
21649c044abSAxel Dörfler }
21749c044abSAxel Dörfler
21849c044abSAxel Dörfler
21949c044abSAxel Dörfler // #pragma mark -
22049c044abSAxel Dörfler
22149c044abSAxel Dörfler
PartitionRecorder(BMessage & settings,int8 biosDrive)22249c044abSAxel Dörfler PartitionRecorder::PartitionRecorder(BMessage& settings, int8 biosDrive)
2235675f44eSAxel Dörfler :
2245675f44eSAxel Dörfler fSettings(settings),
22549c044abSAxel Dörfler fUnnamedIndex(0),
22649c044abSAxel Dörfler fBIOSDrive(biosDrive),
22749c044abSAxel Dörfler fFound(false)
2285675f44eSAxel Dörfler {
2295675f44eSAxel Dörfler }
2305675f44eSAxel Dörfler
2315675f44eSAxel Dörfler
2325675f44eSAxel Dörfler bool
Visit(BDiskDevice * device)2335675f44eSAxel Dörfler PartitionRecorder::Visit(BDiskDevice* device)
2345675f44eSAxel Dörfler {
2355675f44eSAxel Dörfler return false;
2365675f44eSAxel Dörfler }
2375675f44eSAxel Dörfler
2385675f44eSAxel Dörfler
2395675f44eSAxel Dörfler bool
Visit(BPartition * partition,int32 level)2405675f44eSAxel Dörfler PartitionRecorder::Visit(BPartition* partition, int32 level)
2415675f44eSAxel Dörfler {
2425675f44eSAxel Dörfler if (partition->ContainsPartitioningSystem())
2435675f44eSAxel Dörfler return false;
2445675f44eSAxel Dörfler
2455675f44eSAxel Dörfler BPath partitionPath;
2465675f44eSAxel Dörfler partition->GetPath(&partitionPath);
2475675f44eSAxel Dörfler
2485675f44eSAxel Dörfler BString buffer;
249*0449ac1eSOscar Lesta BString name = partition->ContentName();
250*0449ac1eSOscar Lesta if (name.Length() == 0) {
2515675f44eSAxel Dörfler BString number;
25249c044abSAxel Dörfler number << ++fUnnamedIndex;
2535675f44eSAxel Dörfler buffer << B_TRANSLATE_COMMENT("Unnamed %d",
2545675f44eSAxel Dörfler "Default name of a partition whose name could not be read from "
2555675f44eSAxel Dörfler "disk; characters in codepage 437 are allowed only");
2565675f44eSAxel Dörfler buffer.ReplaceFirst("%d", number);
2575675f44eSAxel Dörfler name = buffer.String();
2585675f44eSAxel Dörfler }
2595675f44eSAxel Dörfler
2605675f44eSAxel Dörfler const char* type = partition->Type();
2615675f44eSAxel Dörfler if (type == NULL)
2625675f44eSAxel Dörfler type = B_TRANSLATE_COMMENT("Unknown", "Text is shown for an unknown "
2635675f44eSAxel Dörfler "partition type");
2645675f44eSAxel Dörfler
2655675f44eSAxel Dörfler BMessage message;
2665675f44eSAxel Dörfler // Data as required by BootLoader.h
2675675f44eSAxel Dörfler message.AddBool("show", true);
2685675f44eSAxel Dörfler message.AddString("name", name);
2695675f44eSAxel Dörfler message.AddString("type", type);
2705675f44eSAxel Dörfler message.AddString("path", partitionPath.Path());
27149c044abSAxel Dörfler if (fBIOSDrive != 0)
27249c044abSAxel Dörfler message.AddInt8("drive", fBIOSDrive);
2735675f44eSAxel Dörfler message.AddInt64("size", partition->Size());
27449c044abSAxel Dörfler message.AddInt64("offset", partition->Offset());
2755675f44eSAxel Dörfler
27649c044abSAxel Dörfler fSettings.AddMessage("partition", &message);
27749c044abSAxel Dörfler fFound = true;
2785675f44eSAxel Dörfler
2795675f44eSAxel Dörfler return false;
2805675f44eSAxel Dörfler }
2815675f44eSAxel Dörfler
2825675f44eSAxel Dörfler
28349c044abSAxel Dörfler bool
FoundPartitions() const28449c044abSAxel Dörfler PartitionRecorder::FoundPartitions() const
28549c044abSAxel Dörfler {
28649c044abSAxel Dörfler return fFound;
28749c044abSAxel Dörfler }
28849c044abSAxel Dörfler
28949c044abSAxel Dörfler
2905675f44eSAxel Dörfler // #pragma mark -
2915675f44eSAxel Dörfler
2925675f44eSAxel Dörfler
LegacyBootMenu()2935675f44eSAxel Dörfler LegacyBootMenu::LegacyBootMenu()
2945675f44eSAxel Dörfler {
2955675f44eSAxel Dörfler }
2965675f44eSAxel Dörfler
2975675f44eSAxel Dörfler
~LegacyBootMenu()2985675f44eSAxel Dörfler LegacyBootMenu::~LegacyBootMenu()
2995675f44eSAxel Dörfler {
3005675f44eSAxel Dörfler }
3015675f44eSAxel Dörfler
3025675f44eSAxel Dörfler
3035675f44eSAxel Dörfler bool
IsInstalled(const BootDrive & drive)30449c044abSAxel Dörfler LegacyBootMenu::IsInstalled(const BootDrive& drive)
3055675f44eSAxel Dörfler {
30649c044abSAxel Dörfler // TODO: detect bootman
3075675f44eSAxel Dörfler return false;
3085675f44eSAxel Dörfler }
3095675f44eSAxel Dörfler
3105675f44eSAxel Dörfler
3115675f44eSAxel Dörfler status_t
CanBeInstalled(const BootDrive & drive)31249c044abSAxel Dörfler LegacyBootMenu::CanBeInstalled(const BootDrive& drive)
31349c044abSAxel Dörfler {
31449c044abSAxel Dörfler BDiskDevice device;
31549c044abSAxel Dörfler status_t status = drive.GetDiskDevice(device);
31649c044abSAxel Dörfler if (status != B_OK)
31749c044abSAxel Dörfler return status;
31849c044abSAxel Dörfler
31949c044abSAxel Dörfler PartitionVisitor visitor;
32049c044abSAxel Dörfler device.VisitEachDescendant(&visitor);
32149c044abSAxel Dörfler
32239681c5cSAugustin Cavalier if (!visitor.HasPartitions()
32339681c5cSAugustin Cavalier || strcmp(device.ContentType(), kPartitionTypeIntel) != 0)
3244011cb5dSAdrien Destugues return B_ENTRY_NOT_FOUND;
3254011cb5dSAdrien Destugues
32649c044abSAxel Dörfler // Enough space to write boot menu to drive?
3274011cb5dSAdrien Destugues if (visitor.FirstOffset() < (int)sizeof(kBootLoader))
32849c044abSAxel Dörfler return B_PARTITION_TOO_SMALL;
32949c044abSAxel Dörfler
3308e3ccf2cSRob Gill if (device.IsReadOnlyMedia())
3318e3ccf2cSRob Gill return B_READ_ONLY_DEVICE;
3328e3ccf2cSRob Gill
33349c044abSAxel Dörfler return B_OK;
33449c044abSAxel Dörfler }
33549c044abSAxel Dörfler
33649c044abSAxel Dörfler
33749c044abSAxel Dörfler status_t
CollectPartitions(const BootDrive & drive,BMessage & settings)33849c044abSAxel Dörfler LegacyBootMenu::CollectPartitions(const BootDrive& drive, BMessage& settings)
3395675f44eSAxel Dörfler {
3405675f44eSAxel Dörfler status_t status = B_ERROR;
3415675f44eSAxel Dörfler
34249c044abSAxel Dörfler // Remove previous partitions, if any
34349c044abSAxel Dörfler settings.RemoveName("partition");
34449c044abSAxel Dörfler
3455675f44eSAxel Dörfler BDiskDeviceRoster diskDeviceRoster;
3465675f44eSAxel Dörfler BDiskDevice device;
34749c044abSAxel Dörfler bool partitionsFound = false;
34849c044abSAxel Dörfler
3495675f44eSAxel Dörfler while (diskDeviceRoster.GetNextDevice(&device) == B_OK) {
3505675f44eSAxel Dörfler BPath path;
3515675f44eSAxel Dörfler status_t status = device.GetPath(&path);
3525675f44eSAxel Dörfler if (status != B_OK)
3535675f44eSAxel Dörfler continue;
3545675f44eSAxel Dörfler
35549c044abSAxel Dörfler // Skip not from BIOS bootable drives that are not the target disk
35649c044abSAxel Dörfler int8 biosDrive = 0;
35749c044abSAxel Dörfler if (path != drive.Path()
35849c044abSAxel Dörfler && _GetBIOSDrive(path.Path(), biosDrive) != B_OK)
3595675f44eSAxel Dörfler continue;
3605675f44eSAxel Dörfler
36149c044abSAxel Dörfler PartitionRecorder recorder(settings, biosDrive);
3625675f44eSAxel Dörfler device.VisitEachDescendant(&recorder);
3635675f44eSAxel Dörfler
36449c044abSAxel Dörfler partitionsFound |= recorder.FoundPartitions();
3655675f44eSAxel Dörfler }
3665675f44eSAxel Dörfler
36749c044abSAxel Dörfler return partitionsFound ? B_OK : status;
3685675f44eSAxel Dörfler }
3695675f44eSAxel Dörfler
3705675f44eSAxel Dörfler
3715675f44eSAxel Dörfler status_t
Install(const BootDrive & drive,BMessage & settings)37249c044abSAxel Dörfler LegacyBootMenu::Install(const BootDrive& drive, BMessage& settings)
3735675f44eSAxel Dörfler {
3745675f44eSAxel Dörfler int32 defaultPartitionIndex;
37549c044abSAxel Dörfler if (settings.FindInt32("defaultPartition", &defaultPartitionIndex) != B_OK)
3765675f44eSAxel Dörfler return B_BAD_VALUE;
3775675f44eSAxel Dörfler
3785675f44eSAxel Dörfler int32 timeout;
37949c044abSAxel Dörfler if (settings.FindInt32("timeout", &timeout) != B_OK)
3805675f44eSAxel Dörfler return B_BAD_VALUE;
3815675f44eSAxel Dörfler
38249c044abSAxel Dörfler int fd = open(drive.Path(), O_RDWR);
3835675f44eSAxel Dörfler if (fd < 0)
3845675f44eSAxel Dörfler return B_IO_ERROR;
3855675f44eSAxel Dörfler
3865675f44eSAxel Dörfler MasterBootRecord oldMBR;
3875675f44eSAxel Dörfler if (read(fd, &oldMBR, sizeof(oldMBR)) != sizeof(oldMBR)) {
3885675f44eSAxel Dörfler close(fd);
3895675f44eSAxel Dörfler return B_IO_ERROR;
3905675f44eSAxel Dörfler }
3915675f44eSAxel Dörfler
3925675f44eSAxel Dörfler if (!_IsValid(&oldMBR)) {
3935675f44eSAxel Dörfler close(fd);
3945675f44eSAxel Dörfler return B_BAD_VALUE;
3955675f44eSAxel Dörfler }
3965675f44eSAxel Dörfler
3975675f44eSAxel Dörfler LittleEndianMallocIO newBootLoader;
3985675f44eSAxel Dörfler ssize_t size = sizeof(kBootLoader);
3995675f44eSAxel Dörfler if (newBootLoader.Write(kBootLoader, size) != size) {
4005675f44eSAxel Dörfler close(fd);
4015675f44eSAxel Dörfler return B_NO_MEMORY;
4025675f44eSAxel Dörfler }
4035675f44eSAxel Dörfler
4045675f44eSAxel Dörfler MasterBootRecord* newMBR = (MasterBootRecord*)newBootLoader.Buffer();
4055675f44eSAxel Dörfler _CopyPartitionTable(newMBR, &oldMBR);
4065675f44eSAxel Dörfler
4075675f44eSAxel Dörfler int menuEntries = 0;
4085675f44eSAxel Dörfler int defaultMenuEntry = 0;
4095675f44eSAxel Dörfler BMessage partition;
4105675f44eSAxel Dörfler int32 index;
41149c044abSAxel Dörfler for (index = 0; settings.FindMessage("partition", index,
4125675f44eSAxel Dörfler &partition) == B_OK; index ++) {
4135675f44eSAxel Dörfler bool show;
4145675f44eSAxel Dörfler partition.FindBool("show", &show);
4155675f44eSAxel Dörfler if (!show)
4165675f44eSAxel Dörfler continue;
4175675f44eSAxel Dörfler if (index == defaultPartitionIndex)
4185675f44eSAxel Dörfler defaultMenuEntry = menuEntries;
4195675f44eSAxel Dörfler
4205675f44eSAxel Dörfler menuEntries ++;
4215675f44eSAxel Dörfler }
4225675f44eSAxel Dörfler newBootLoader.WriteInt16(menuEntries);
4235675f44eSAxel Dörfler newBootLoader.WriteInt16(defaultMenuEntry);
4245675f44eSAxel Dörfler newBootLoader.WriteInt16(timeout);
4255675f44eSAxel Dörfler
42649c044abSAxel Dörfler for (index = 0; settings.FindMessage("partition", index,
4275675f44eSAxel Dörfler &partition) == B_OK; index ++) {
4285675f44eSAxel Dörfler bool show;
4295675f44eSAxel Dörfler BString name;
4305675f44eSAxel Dörfler BString path;
4315675f44eSAxel Dörfler int64 offset;
4325675f44eSAxel Dörfler int8 drive;
4335675f44eSAxel Dörfler partition.FindBool("show", &show);
4345675f44eSAxel Dörfler partition.FindString("name", &name);
4355675f44eSAxel Dörfler partition.FindString("path", &path);
4365675f44eSAxel Dörfler // LegacyBootMenu specific data
4375675f44eSAxel Dörfler partition.FindInt64("offset", &offset);
4385675f44eSAxel Dörfler partition.FindInt8("drive", &drive);
4395675f44eSAxel Dörfler if (!show)
4405675f44eSAxel Dörfler continue;
4415675f44eSAxel Dörfler
4425675f44eSAxel Dörfler BString biosName;
4435675f44eSAxel Dörfler _ConvertToBIOSText(name.String(), biosName);
4445675f44eSAxel Dörfler
4455675f44eSAxel Dörfler newBootLoader.WriteString(biosName.String());
4465675f44eSAxel Dörfler newBootLoader.WriteInt8(drive);
4475675f44eSAxel Dörfler newBootLoader.WriteInt64(offset / kBlockSize);
4485675f44eSAxel Dörfler }
4495675f44eSAxel Dörfler
4505675f44eSAxel Dörfler if (!newBootLoader.Align(kBlockSize)) {
4515675f44eSAxel Dörfler close(fd);
4525675f44eSAxel Dörfler return B_ERROR;
4535675f44eSAxel Dörfler }
4545675f44eSAxel Dörfler
4555675f44eSAxel Dörfler lseek(fd, 0, SEEK_SET);
4565675f44eSAxel Dörfler const uint8* buffer = (const uint8*)newBootLoader.Buffer();
4575675f44eSAxel Dörfler status_t status = _WriteBlocks(fd, buffer, newBootLoader.Position());
4585675f44eSAxel Dörfler close(fd);
4595675f44eSAxel Dörfler return status;
4605675f44eSAxel Dörfler }
4615675f44eSAxel Dörfler
4625675f44eSAxel Dörfler
4635675f44eSAxel Dörfler status_t
SaveMasterBootRecord(BMessage * settings,BFile * file)4645675f44eSAxel Dörfler LegacyBootMenu::SaveMasterBootRecord(BMessage* settings, BFile* file)
4655675f44eSAxel Dörfler {
4665675f44eSAxel Dörfler BString path;
4675675f44eSAxel Dörfler
4685675f44eSAxel Dörfler if (settings->FindString("disk", &path) != B_OK)
4695675f44eSAxel Dörfler return B_BAD_VALUE;
4705675f44eSAxel Dörfler
4715675f44eSAxel Dörfler int fd = open(path.String(), O_RDONLY);
4725675f44eSAxel Dörfler if (fd < 0)
4735675f44eSAxel Dörfler return B_IO_ERROR;
4745675f44eSAxel Dörfler
4755675f44eSAxel Dörfler ssize_t size = kBlockSize * kNumberOfBootLoaderBlocks;
4765675f44eSAxel Dörfler uint8* buffer = new(std::nothrow) uint8[size];
4775675f44eSAxel Dörfler if (buffer == NULL) {
4785675f44eSAxel Dörfler close(fd);
4795675f44eSAxel Dörfler return B_NO_MEMORY;
4805675f44eSAxel Dörfler }
4815675f44eSAxel Dörfler
4825675f44eSAxel Dörfler status_t status = _ReadBlocks(fd, buffer, size);
4835675f44eSAxel Dörfler if (status != B_OK) {
4845675f44eSAxel Dörfler close(fd);
4855675f44eSAxel Dörfler delete[] buffer;
4865675f44eSAxel Dörfler return B_IO_ERROR;
4875675f44eSAxel Dörfler }
4885675f44eSAxel Dörfler
4895675f44eSAxel Dörfler MasterBootRecord* mbr = (MasterBootRecord*)buffer;
4905675f44eSAxel Dörfler if (!_IsValid(mbr)) {
4915675f44eSAxel Dörfler close(fd);
4925675f44eSAxel Dörfler delete[] buffer;
4935675f44eSAxel Dörfler return B_BAD_VALUE;
4945675f44eSAxel Dörfler }
4955675f44eSAxel Dörfler
4965675f44eSAxel Dörfler if (file->Write(buffer, size) != size)
4975675f44eSAxel Dörfler status = B_IO_ERROR;
4985675f44eSAxel Dörfler delete[] buffer;
4995675f44eSAxel Dörfler close(fd);
5005675f44eSAxel Dörfler return status;
5015675f44eSAxel Dörfler }
5025675f44eSAxel Dörfler
5035675f44eSAxel Dörfler
5045675f44eSAxel Dörfler status_t
RestoreMasterBootRecord(BMessage * settings,BFile * file)5055675f44eSAxel Dörfler LegacyBootMenu::RestoreMasterBootRecord(BMessage* settings, BFile* file)
5065675f44eSAxel Dörfler {
5075675f44eSAxel Dörfler BString path;
5085675f44eSAxel Dörfler if (settings->FindString("disk", &path) != B_OK)
5095675f44eSAxel Dörfler return B_BAD_VALUE;
5105675f44eSAxel Dörfler
5115675f44eSAxel Dörfler int fd = open(path.String(), O_RDWR);
5125675f44eSAxel Dörfler if (fd < 0)
5135675f44eSAxel Dörfler return B_IO_ERROR;
5145675f44eSAxel Dörfler
5155675f44eSAxel Dörfler MasterBootRecord oldMBR;
5165675f44eSAxel Dörfler if (read(fd, &oldMBR, sizeof(oldMBR)) != sizeof(oldMBR)) {
5175675f44eSAxel Dörfler close(fd);
5185675f44eSAxel Dörfler return B_IO_ERROR;
5195675f44eSAxel Dörfler }
5205675f44eSAxel Dörfler if (!_IsValid(&oldMBR)) {
5215675f44eSAxel Dörfler close(fd);
5225675f44eSAxel Dörfler return B_BAD_VALUE;
5235675f44eSAxel Dörfler }
5245675f44eSAxel Dörfler
5255675f44eSAxel Dörfler lseek(fd, 0, SEEK_SET);
5265675f44eSAxel Dörfler
5275675f44eSAxel Dörfler size_t size = kBlockSize * kNumberOfBootLoaderBlocks;
5285675f44eSAxel Dörfler uint8* buffer = new(std::nothrow) uint8[size];
5295675f44eSAxel Dörfler if (buffer == NULL) {
5305675f44eSAxel Dörfler close(fd);
5315675f44eSAxel Dörfler return B_NO_MEMORY;
5325675f44eSAxel Dörfler }
5335675f44eSAxel Dörfler
5345675f44eSAxel Dörfler if (file->Read(buffer, size) != (ssize_t)size) {
5355675f44eSAxel Dörfler close(fd);
5365675f44eSAxel Dörfler delete[] buffer;
5375675f44eSAxel Dörfler return B_IO_ERROR;
5385675f44eSAxel Dörfler }
5395675f44eSAxel Dörfler
5405675f44eSAxel Dörfler MasterBootRecord* newMBR = (MasterBootRecord*)buffer;
5415675f44eSAxel Dörfler if (!_IsValid(newMBR)) {
5425675f44eSAxel Dörfler close(fd);
5435675f44eSAxel Dörfler delete[] buffer;
5445675f44eSAxel Dörfler return B_BAD_VALUE;
5455675f44eSAxel Dörfler }
5465675f44eSAxel Dörfler
5475675f44eSAxel Dörfler _CopyPartitionTable(newMBR, &oldMBR);
5485675f44eSAxel Dörfler
5495675f44eSAxel Dörfler status_t status = _WriteBlocks(fd, buffer, size);
5505675f44eSAxel Dörfler delete[] buffer;
5515675f44eSAxel Dörfler close(fd);
5525675f44eSAxel Dörfler return status;
5535675f44eSAxel Dörfler }
5545675f44eSAxel Dörfler
5555675f44eSAxel Dörfler
5565675f44eSAxel Dörfler status_t
GetDisplayText(const char * text,BString & displayText)5575675f44eSAxel Dörfler LegacyBootMenu::GetDisplayText(const char* text, BString& displayText)
5585675f44eSAxel Dörfler {
5595675f44eSAxel Dörfler BString biosText;
5605675f44eSAxel Dörfler if (!_ConvertToBIOSText(text, biosText)) {
5615675f44eSAxel Dörfler displayText = "???";
5625675f44eSAxel Dörfler return B_ERROR;
5635675f44eSAxel Dörfler }
5645675f44eSAxel Dörfler
5655675f44eSAxel Dörfler // convert back to UTF-8
5665675f44eSAxel Dörfler int32 biosTextLength = biosText.Length();
5675675f44eSAxel Dörfler int32 bufferLength = strlen(text);
5685675f44eSAxel Dörfler char* buffer = displayText.LockBuffer(bufferLength + 1);
5695675f44eSAxel Dörfler int32 state = 0;
5705675f44eSAxel Dörfler if (convert_to_utf8(B_MS_DOS_CONVERSION,
5715675f44eSAxel Dörfler biosText.String(), &biosTextLength,
5725675f44eSAxel Dörfler buffer, &bufferLength, &state) != B_OK) {
5735675f44eSAxel Dörfler displayText.UnlockBuffer(0);
5745675f44eSAxel Dörfler displayText = "???";
5755675f44eSAxel Dörfler return B_ERROR;
5765675f44eSAxel Dörfler }
5775675f44eSAxel Dörfler
5785675f44eSAxel Dörfler buffer[bufferLength] = '\0';
5795675f44eSAxel Dörfler displayText.UnlockBuffer(bufferLength);
5805675f44eSAxel Dörfler return B_OK;
5815675f44eSAxel Dörfler }
5825675f44eSAxel Dörfler
5835675f44eSAxel Dörfler
5845675f44eSAxel Dörfler bool
_ConvertToBIOSText(const char * text,BString & biosText)5855675f44eSAxel Dörfler LegacyBootMenu::_ConvertToBIOSText(const char* text, BString& biosText)
5865675f44eSAxel Dörfler {
5875675f44eSAxel Dörfler // convert text in UTF-8 to 'code page 437'
5885675f44eSAxel Dörfler int32 textLength = strlen(text);
5895675f44eSAxel Dörfler
5905675f44eSAxel Dörfler int32 biosTextLength = textLength;
5915675f44eSAxel Dörfler char* buffer = biosText.LockBuffer(biosTextLength + 1);
5925675f44eSAxel Dörfler if (buffer == NULL) {
5935675f44eSAxel Dörfler biosText.UnlockBuffer(0);
5945675f44eSAxel Dörfler return false;
5955675f44eSAxel Dörfler }
5965675f44eSAxel Dörfler
5975675f44eSAxel Dörfler int32 state = 0;
5985675f44eSAxel Dörfler if (convert_from_utf8(B_MS_DOS_CONVERSION, text, &textLength,
5995675f44eSAxel Dörfler buffer, &biosTextLength, &state) != B_OK) {
6005675f44eSAxel Dörfler biosText.UnlockBuffer(0);
6015675f44eSAxel Dörfler return false;
6025675f44eSAxel Dörfler }
6035675f44eSAxel Dörfler
6045675f44eSAxel Dörfler buffer[biosTextLength] = '\0';
6055675f44eSAxel Dörfler biosText.UnlockBuffer(biosTextLength);
6065675f44eSAxel Dörfler return biosTextLength < kMaxBootMenuItemLength;
6075675f44eSAxel Dörfler }
6085675f44eSAxel Dörfler
6095675f44eSAxel Dörfler
61049c044abSAxel Dörfler status_t
_GetBIOSDrive(const char * device,int8 & drive)61149c044abSAxel Dörfler LegacyBootMenu::_GetBIOSDrive(const char* device, int8& drive)
6125675f44eSAxel Dörfler {
6135675f44eSAxel Dörfler int fd = open(device, O_RDONLY);
6145675f44eSAxel Dörfler if (fd < 0)
61549c044abSAxel Dörfler return errno;
61649c044abSAxel Dörfler
6174c9e8f77SAugustin Cavalier status_t status = ioctl(fd, B_GET_BIOS_DRIVE_ID, &drive, 1);
6185675f44eSAxel Dörfler close(fd);
61949c044abSAxel Dörfler return status;
6205675f44eSAxel Dörfler }
6215675f44eSAxel Dörfler
6225675f44eSAxel Dörfler
6235675f44eSAxel Dörfler status_t
_ReadBlocks(int fd,uint8 * buffer,size_t size)6245675f44eSAxel Dörfler LegacyBootMenu::_ReadBlocks(int fd, uint8* buffer, size_t size)
6255675f44eSAxel Dörfler {
6265675f44eSAxel Dörfler if (size % kBlockSize != 0) {
6275675f44eSAxel Dörfler fprintf(stderr, "_ReadBlocks buffer size must be a multiple of %d\n",
6285675f44eSAxel Dörfler (int)kBlockSize);
6295675f44eSAxel Dörfler return B_BAD_VALUE;
6305675f44eSAxel Dörfler }
6315675f44eSAxel Dörfler const size_t blocks = size / kBlockSize;
6325675f44eSAxel Dörfler uint8* block = buffer;
6335675f44eSAxel Dörfler for (size_t i = 0; i < blocks; i ++, block += kBlockSize) {
6345675f44eSAxel Dörfler if (read(fd, block, kBlockSize) != (ssize_t)kBlockSize)
6355675f44eSAxel Dörfler return B_IO_ERROR;
6365675f44eSAxel Dörfler }
6375675f44eSAxel Dörfler return B_OK;
6385675f44eSAxel Dörfler }
6395675f44eSAxel Dörfler
6405675f44eSAxel Dörfler
6415675f44eSAxel Dörfler status_t
_WriteBlocks(int fd,const uint8 * buffer,size_t size)6425675f44eSAxel Dörfler LegacyBootMenu::_WriteBlocks(int fd, const uint8* buffer, size_t size)
6435675f44eSAxel Dörfler {
6445675f44eSAxel Dörfler if (size % kBlockSize != 0) {
6455675f44eSAxel Dörfler fprintf(stderr, "_WriteBlocks buffer size must be a multiple of %d\n",
6465675f44eSAxel Dörfler (int)kBlockSize);
6475675f44eSAxel Dörfler return B_BAD_VALUE;
6485675f44eSAxel Dörfler }
6495675f44eSAxel Dörfler const size_t blocks = size / kBlockSize;
6505675f44eSAxel Dörfler const uint8* block = buffer;
6515675f44eSAxel Dörfler for (size_t i = 0; i < blocks; i ++, block += kBlockSize) {
6525675f44eSAxel Dörfler if (write(fd, block, kBlockSize) != (ssize_t)kBlockSize)
6535675f44eSAxel Dörfler return B_IO_ERROR;
6545675f44eSAxel Dörfler }
6555675f44eSAxel Dörfler return B_OK;
6565675f44eSAxel Dörfler }
6575675f44eSAxel Dörfler
6585675f44eSAxel Dörfler
6595675f44eSAxel Dörfler void
_CopyPartitionTable(MasterBootRecord * destination,const MasterBootRecord * source)6605675f44eSAxel Dörfler LegacyBootMenu::_CopyPartitionTable(MasterBootRecord* destination,
6615675f44eSAxel Dörfler const MasterBootRecord* source)
6625675f44eSAxel Dörfler {
6635675f44eSAxel Dörfler memcpy(destination->diskSignature, source->diskSignature,
6645675f44eSAxel Dörfler sizeof(source->diskSignature) + sizeof(source->reserved)
6655675f44eSAxel Dörfler + sizeof(source->partition));
6665675f44eSAxel Dörfler }
6675675f44eSAxel Dörfler
6685675f44eSAxel Dörfler
6695675f44eSAxel Dörfler bool
_IsValid(const MasterBootRecord * mbr)6705675f44eSAxel Dörfler LegacyBootMenu::_IsValid(const MasterBootRecord* mbr)
6715675f44eSAxel Dörfler {
6725675f44eSAxel Dörfler return mbr->signature[0] == (kMBRSignature & 0xff)
6735675f44eSAxel Dörfler && mbr->signature[1] == (kMBRSignature >> 8);
6745675f44eSAxel Dörfler }
675