xref: /haiku/src/apps/bootmanager/LegacyBootMenu.cpp (revision 2710b4f5d4251c5cf88c82b0114ea99b0ef46d22)
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