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