1338b8dc3SIngo Weinhold/*
2f1f6eacdSIngo Weinhold * Copyright 2005-2009, Ingo Weinhold, ingo_weinhold@gmx.de.
3338b8dc3SIngo Weinhold * Distributed under the terms of the MIT License.
4338b8dc3SIngo Weinhold */
5338b8dc3SIngo Weinhold
6f1f6eacdSIngo Weinhold
7338b8dc3SIngo Weinhold#include <errno.h>
8338b8dc3SIngo Weinhold#include <fcntl.h>
9338b8dc3SIngo Weinhold#include <stdio.h>
10338b8dc3SIngo Weinhold#include <stdlib.h>
11338b8dc3SIngo Weinhold#include <string.h>
12338b8dc3SIngo Weinhold#include <unistd.h>
13338b8dc3SIngo Weinhold#include <sys/stat.h>
14338b8dc3SIngo Weinhold
15338b8dc3SIngo Weinhold#include <ByteOrder.h>
16338b8dc3SIngo Weinhold#include <Drivers.h>
17338b8dc3SIngo Weinhold#include <Entry.h>
18338b8dc3SIngo Weinhold#include <File.h>
19338b8dc3SIngo Weinhold#include <fs_info.h>
20338b8dc3SIngo Weinhold#include <Resources.h>
21338b8dc3SIngo Weinhold#include <TypeConstants.h>
22338b8dc3SIngo Weinhold
2380b2da5eSIngo Weinhold// Linux and FreeBSD support
2404fcc147SIngo Weinhold#ifdef HAIKU_HOST_PLATFORM_LINUX
2504fcc147SIngo Weinhold#	include <ctype.h>
26fb7c02c2SIngo Weinhold#	include <linux/fs.h>
2704fcc147SIngo Weinhold#	include <linux/hdreg.h>
2804fcc147SIngo Weinhold#	include <sys/ioctl.h>
2904fcc147SIngo Weinhold
30f1f6eacdSIngo Weinhold#	define USE_PARTITION_MAP 1
3180b2da5eSIngo Weinhold#elif HAIKU_HOST_PLATFORM_FREEBSD
3280b2da5eSIngo Weinhold#	include <ctype.h>
3380b2da5eSIngo Weinhold#	include <sys/disklabel.h>
3480b2da5eSIngo Weinhold#	include <sys/disk.h>
3580b2da5eSIngo Weinhold#	include <sys/ioctl.h>
3680b2da5eSIngo Weinhold
37f1f6eacdSIngo Weinhold#	define USE_PARTITION_MAP 1
3821055357SIngo Weinhold#elif HAIKU_HOST_PLATFORM_DARWIN
3921055357SIngo Weinhold#	include <ctype.h>
4021055357SIngo Weinhold#	include <sys/disk.h>
4121055357SIngo Weinhold#	include <sys/ioctl.h>
4221055357SIngo Weinhold
43f1f6eacdSIngo Weinhold#	define USE_PARTITION_MAP 1
446296f36bSRene Gollent#endif
456296f36bSRene Gollent
46204dee70SIngo Weinhold#ifdef HAIKU_TARGET_PLATFORM_HAIKU
4799b25014SRene Gollent#	include <image.h>
48c7cf1688SAxel Dörfler
49c7cf1688SAxel Dörfler#	include <DiskDevice.h>
50c7cf1688SAxel Dörfler#	include <DiskDeviceRoster.h>
51c7cf1688SAxel Dörfler#	include <Partition.h>
52c7cf1688SAxel Dörfler#	include <Path.h>
53c7cf1688SAxel Dörfler
54c7cf1688SAxel Dörfler#	include "bfs_control.h"
5580b2da5eSIngo Weinhold#endif
5604fcc147SIngo Weinhold
57f1f6eacdSIngo Weinhold#if USE_PARTITION_MAP
5842f25fe9SJessica Hamilton#	include "guid.h"
5942f25fe9SJessica Hamilton#	include "gpt_known_guids.h"
6042f25fe9SJessica Hamilton#	include "Header.h"
61f1f6eacdSIngo Weinhold#	include "PartitionMap.h"
62f1f6eacdSIngo Weinhold#	include "PartitionMapParser.h"
63f1f6eacdSIngo Weinhold#endif
64f1f6eacdSIngo Weinhold
6504fcc147SIngo Weinhold
66338b8dc3SIngo Weinholdstatic const char *kCommandName = "makebootable";
67338b8dc3SIngo Weinhold
68338b8dc3SIngo Weinholdstatic const int kBootCodeSize				= 1024;
69338b8dc3SIngo Weinholdstatic const int kFirstBootCodePartSize		= 512;
70c7cf1688SAxel Dörflerstatic const int kSecondBootCodePartOffset	= 676;
71c7cf1688SAxel Dörflerstatic const int kSecondBootCodePartSize	= kBootCodeSize
72c7cf1688SAxel Dörfler												- kSecondBootCodePartOffset;
73338b8dc3SIngo Weinholdstatic const int kPartitionOffsetOffset		= 506;
74338b8dc3SIngo Weinhold
75338b8dc3SIngo Weinholdstatic int kArgc;
76338b8dc3SIngo Weinholdstatic const char *const *kArgv;
77338b8dc3SIngo Weinhold
78338b8dc3SIngo Weinhold// usage
79338b8dc3SIngo Weinholdconst char *kUsage =
80338b8dc3SIngo Weinhold"Usage: %s [ options ] <file> ...\n"
81338b8dc3SIngo Weinhold"\n"
82338b8dc3SIngo Weinhold"Makes the specified BFS partitions/devices bootable by writing boot code\n"
83338b8dc3SIngo Weinhold"into the first two sectors. It doesn't mark the partition(s) active.\n"
84338b8dc3SIngo Weinhold"\n"
85338b8dc3SIngo Weinhold"If a given <file> refers to a directory, the partition/device on which the\n"
86338b8dc3SIngo Weinhold"directory resides will be made bootable. If it refers to a regular file,\n"
87338b8dc3SIngo Weinhold"the file is considered a disk image and the boot code will be written to\n"
88338b8dc3SIngo Weinhold"it.\n"
89338b8dc3SIngo Weinhold"\n"
90338b8dc3SIngo Weinhold"Options:\n"
91338b8dc3SIngo Weinhold"  -h, --help    - Print this help text and exit.\n"
9204fcc147SIngo Weinhold"  --dry-run     - Do everything but actually writing the boot block to disk.\n"
93338b8dc3SIngo Weinhold;
94338b8dc3SIngo Weinhold
9539bdbadfSIngo Weinhold
96338b8dc3SIngo Weinhold// print_usage
97338b8dc3SIngo Weinholdstatic void
98338b8dc3SIngo Weinholdprint_usage(bool error)
99338b8dc3SIngo Weinhold{
100338b8dc3SIngo Weinhold	// get command name
101338b8dc3SIngo Weinhold	const char *commandName = NULL;
102338b8dc3SIngo Weinhold	if (kArgc > 0) {
103338b8dc3SIngo Weinhold		if (const char *lastSlash = strchr(kArgv[0], '/'))
104338b8dc3SIngo Weinhold			commandName = lastSlash + 1;
105338b8dc3SIngo Weinhold		else
106338b8dc3SIngo Weinhold			commandName = kArgv[0];
107338b8dc3SIngo Weinhold	}
108338b8dc3SIngo Weinhold
109338b8dc3SIngo Weinhold	if (!commandName || strlen(commandName) == 0)
110338b8dc3SIngo Weinhold		commandName = kCommandName;
111338b8dc3SIngo Weinhold
112338b8dc3SIngo Weinhold	// print usage
113338b8dc3SIngo Weinhold	fprintf((error ? stderr : stdout), kUsage, commandName, commandName,
114338b8dc3SIngo Weinhold		commandName);
115338b8dc3SIngo Weinhold}
116338b8dc3SIngo Weinhold
11739bdbadfSIngo Weinhold
118338b8dc3SIngo Weinhold// print_usage_and_exit
119338b8dc3SIngo Weinholdstatic void
120338b8dc3SIngo Weinholdprint_usage_and_exit(bool error)
121338b8dc3SIngo Weinhold{
122338b8dc3SIngo Weinhold	print_usage(error);
123338b8dc3SIngo Weinhold	exit(error ? 1 : 0);
124338b8dc3SIngo Weinhold}
125338b8dc3SIngo Weinhold
12639bdbadfSIngo Weinhold
12739bdbadfSIngo Weinhold// read_boot_code_data
12839bdbadfSIngo Weinholdstatic uint8 *
12999b25014SRene Gollentread_boot_code_data(const char* programPath)
13039bdbadfSIngo Weinhold{
13199b25014SRene Gollent	// open our executable
13239bdbadfSIngo Weinhold	BFile executableFile;
13399b25014SRene Gollent	status_t error = executableFile.SetTo(programPath, B_READ_ONLY);
13499b25014SRene Gollent	if (error != B_OK) {
13599b25014SRene Gollent		fprintf(stderr, "Error: Failed to open my executable file (\"%s\": "
13699b25014SRene Gollent			"%s\n", programPath, strerror(error));
13739bdbadfSIngo Weinhold		exit(1);
13839bdbadfSIngo Weinhold	}
13999b25014SRene Gollent
14039bdbadfSIngo Weinhold	uint8 *bootCodeData = new uint8[kBootCodeSize];
14139bdbadfSIngo Weinhold
14239bdbadfSIngo Weinhold	// open our resources
14339bdbadfSIngo Weinhold	BResources resources;
14439bdbadfSIngo Weinhold	error = resources.SetTo(&executableFile);
14539bdbadfSIngo Weinhold	const void *resourceData = NULL;
14639bdbadfSIngo Weinhold	if (error == B_OK) {
14739bdbadfSIngo Weinhold		// read the boot block from the resources
14839bdbadfSIngo Weinhold		size_t resourceSize;
14939bdbadfSIngo Weinhold		resourceData = resources.LoadResource(B_RAW_TYPE, 666, &resourceSize);
15039bdbadfSIngo Weinhold
15139bdbadfSIngo Weinhold		if (resourceData && resourceSize != (size_t)kBootCodeSize) {
15239bdbadfSIngo Weinhold			resourceData = NULL;
15339bdbadfSIngo Weinhold			printf("Warning: Something is fishy with my resources! The boot "
15439bdbadfSIngo Weinhold				"code doesn't have the correct size. Trying the attribute "
15539bdbadfSIngo Weinhold				"instead ...\n");
15639bdbadfSIngo Weinhold		}
15739bdbadfSIngo Weinhold	}
15839bdbadfSIngo Weinhold
15939bdbadfSIngo Weinhold	if (resourceData) {
16039bdbadfSIngo Weinhold		// found boot data in the resources
16139bdbadfSIngo Weinhold		memcpy(bootCodeData, resourceData, kBootCodeSize);
16239bdbadfSIngo Weinhold	} else {
16339bdbadfSIngo Weinhold		// no boot data in the resources; try the attribute
16439bdbadfSIngo Weinhold		ssize_t bytesRead = executableFile.ReadAttr("BootCode", B_RAW_TYPE,
16539bdbadfSIngo Weinhold			0, bootCodeData, kBootCodeSize);
16639bdbadfSIngo Weinhold		if (bytesRead < 0) {
16739bdbadfSIngo Weinhold			fprintf(stderr, "Error: Failed to read boot code from resources "
1681d467366SFredrik Modeen				"or attribute.\n");
16939bdbadfSIngo Weinhold			exit(1);
17039bdbadfSIngo Weinhold		}
17139bdbadfSIngo Weinhold		if (bytesRead != kBootCodeSize) {
17239bdbadfSIngo Weinhold			fprintf(stderr, "Error: Failed to read boot code from resources, "
1731d467366SFredrik Modeen				"and the boot code in the attribute has the wrong size!\n");
17439bdbadfSIngo Weinhold			exit(1);
17539bdbadfSIngo Weinhold		}
17639bdbadfSIngo Weinhold	}
17739bdbadfSIngo Weinhold
17839bdbadfSIngo Weinhold	return bootCodeData;
17939bdbadfSIngo Weinhold}
18039bdbadfSIngo Weinhold
18139bdbadfSIngo Weinhold
182338b8dc3SIngo Weinhold// write_boot_code_part
183338b8dc3SIngo Weinholdstatic void
184a17d1cf4SIngo Weinholdwrite_boot_code_part(const char *fileName, int fd, off_t imageOffset,
185a17d1cf4SIngo Weinhold	const uint8 *bootCodeData, int offset, int size, bool dryRun)
186338b8dc3SIngo Weinhold{
18704fcc147SIngo Weinhold	if (!dryRun) {
188a17d1cf4SIngo Weinhold		ssize_t bytesWritten = write_pos(fd, imageOffset + offset,
189a17d1cf4SIngo Weinhold			bootCodeData + offset, size);
19004fcc147SIngo Weinhold		if (bytesWritten != size) {
19104fcc147SIngo Weinhold			fprintf(stderr, "Error: Failed to write to \"%s\": %s\n", fileName,
19204fcc147SIngo Weinhold				strerror(bytesWritten < 0 ? errno : B_ERROR));
19304fcc147SIngo Weinhold		}
194338b8dc3SIngo Weinhold	}
195338b8dc3SIngo Weinhold}
196338b8dc3SIngo Weinhold
19739bdbadfSIngo Weinhold
198204dee70SIngo Weinhold#ifdef HAIKU_TARGET_PLATFORM_HAIKU
199f1f6eacdSIngo Weinhold
200da3c3879SRene Gollentstatic status_t
201da3c3879SRene Gollentfind_own_image(image_info *info)
202da3c3879SRene Gollent{
203da3c3879SRene Gollent	int32 cookie = 0;
204da3c3879SRene Gollent	while (get_next_image_info(B_CURRENT_TEAM, &cookie, info) == B_OK) {
205c7cf1688SAxel Dörfler		if (((addr_t)info->text <= (addr_t)find_own_image
206c7cf1688SAxel Dörfler			&& (addr_t)info->text + info->text_size
207878cc304SRene Gollent				> (addr_t)find_own_image)) {
208da3c3879SRene Gollent			return B_OK;
209da3c3879SRene Gollent		}
210da3c3879SRene Gollent	}
211da3c3879SRene Gollent
212da3c3879SRene Gollent	return B_NAME_NOT_FOUND;
213da3c3879SRene Gollent}
214f1f6eacdSIngo Weinhold
215f1f6eacdSIngo Weinhold#endif
216f1f6eacdSIngo Weinhold
217f1f6eacdSIngo Weinhold
218f1f6eacdSIngo Weinhold#if USE_PARTITION_MAP
219f1f6eacdSIngo Weinhold
220f1f6eacdSIngo Weinholdstatic void
221f1f6eacdSIngo Weinholddump_partition_map(const PartitionMap& map)
222f1f6eacdSIngo Weinhold{
223f1f6eacdSIngo Weinhold	fprintf(stderr, "partitions:\n");
224f1f6eacdSIngo Weinhold	int32 count = map.CountPartitions();
225f1f6eacdSIngo Weinhold	for (int i = 0; i < count; i++) {
226f1f6eacdSIngo Weinhold		const Partition* partition = map.PartitionAt(i);
227f1f6eacdSIngo Weinhold		fprintf(stderr, "%2d: ", i);
228f1f6eacdSIngo Weinhold		if (partition == NULL) {
229f1f6eacdSIngo Weinhold			fprintf(stderr, "<null>\n");
230f1f6eacdSIngo Weinhold			continue;
231f1f6eacdSIngo Weinhold		}
232f1f6eacdSIngo Weinhold
233f1f6eacdSIngo Weinhold		if (partition->IsEmpty()) {
234f1f6eacdSIngo Weinhold			fprintf(stderr, "<empty>\n");
235f1f6eacdSIngo Weinhold			continue;
236f1f6eacdSIngo Weinhold		}
237f1f6eacdSIngo Weinhold
238cf844822SIngo Weinhold		fprintf(stderr, "offset: %16" B_PRIdOFF ", size: %16" B_PRIdOFF
239cf844822SIngo Weinhold			", type: %x%s\n", partition->Offset(), partition->Size(),
240f1f6eacdSIngo Weinhold			partition->Type(), partition->IsExtended() ? " (extended)" : "");
241f1f6eacdSIngo Weinhold	}
242f1f6eacdSIngo Weinhold}
243f1f6eacdSIngo Weinhold
24442f25fe9SJessica Hamilton
24542f25fe9SJessica Hamiltonstatic void
24642f25fe9SJessica Hamiltonget_partition_offset(int deviceFD, off_t deviceStart, off_t deviceSize,
24742f25fe9SJessica Hamilton		int blockSize, int partitionIndex, char *deviceName,
24842f25fe9SJessica Hamilton		int64 &_partitionOffset)
24942f25fe9SJessica Hamilton{
25042f25fe9SJessica Hamilton	PartitionMapParser parser(deviceFD, deviceStart, deviceSize, blockSize);
25142f25fe9SJessica Hamilton	PartitionMap map;
25242f25fe9SJessica Hamilton	status_t error = parser.Parse(NULL, &map);
25342f25fe9SJessica Hamilton	if (error == B_OK) {
25442f25fe9SJessica Hamilton		Partition *partition = map.PartitionAt(partitionIndex - 1);
25542f25fe9SJessica Hamilton		if (!partition || partition->IsEmpty()) {
25642f25fe9SJessica Hamilton			fprintf(stderr, "Error: Invalid partition index %d.\n",
25742f25fe9SJessica Hamilton				partitionIndex);
25842f25fe9SJessica Hamilton			dump_partition_map(map);
25942f25fe9SJessica Hamilton			exit(1);
26042f25fe9SJessica Hamilton		}
26142f25fe9SJessica Hamilton
26242f25fe9SJessica Hamilton		if (partition->IsExtended()) {
26342f25fe9SJessica Hamilton			fprintf(stderr, "Error: Partition %d is an extended "
26442f25fe9SJessica Hamilton				"partition.\n", partitionIndex);
26542f25fe9SJessica Hamilton			dump_partition_map(map);
26642f25fe9SJessica Hamilton			exit(1);
26742f25fe9SJessica Hamilton		}
26842f25fe9SJessica Hamilton
26942f25fe9SJessica Hamilton		_partitionOffset = partition->Offset();
27042f25fe9SJessica Hamilton	} else {
27142f25fe9SJessica Hamilton		// try again using GPT instead
27242f25fe9SJessica Hamilton		EFI::Header gptHeader(deviceFD, deviceSize, blockSize);
27342f25fe9SJessica Hamilton		error = gptHeader.InitCheck();
27442f25fe9SJessica Hamilton		if (error == B_OK && partitionIndex < gptHeader.EntryCount()) {
27542f25fe9SJessica Hamilton			efi_partition_entry partition = gptHeader.EntryAt(partitionIndex - 1);
27642f25fe9SJessica Hamilton
27742f25fe9SJessica Hamilton			static_guid bfs_uuid = {0x42465331, 0x3BA3, 0x10F1,
27842f25fe9SJessica Hamilton				0x802A4861696B7521LL};
27942f25fe9SJessica Hamilton
28042f25fe9SJessica Hamilton			if (!(bfs_uuid == partition.partition_type)) {
28142f25fe9SJessica Hamilton				fprintf(stderr, "Error: Partition %d does not have the "
28242f25fe9SJessica Hamilton					"BFS UUID.\n", partitionIndex);
28342f25fe9SJessica Hamilton				exit(1);
28442f25fe9SJessica Hamilton			}
28542f25fe9SJessica Hamilton
28642f25fe9SJessica Hamilton			_partitionOffset = partition.StartBlock() * blockSize;
28742f25fe9SJessica Hamilton		} else {
28842f25fe9SJessica Hamilton			fprintf(stderr, "Error: Parsing partition table on device "
28942f25fe9SJessica Hamilton				"\"%s\" failed: %s\n", deviceName, strerror(error));
29042f25fe9SJessica Hamilton			exit(1);
29142f25fe9SJessica Hamilton		}
29242f25fe9SJessica Hamilton	}
29342f25fe9SJessica Hamilton
29442f25fe9SJessica Hamilton	close(deviceFD);
29542f25fe9SJessica Hamilton}
29642f25fe9SJessica Hamilton
297da3c3879SRene Gollent#endif
298da3c3879SRene Gollent
299da3c3879SRene Gollent
300338b8dc3SIngo Weinhold// main
301338b8dc3SIngo Weinholdint
302338b8dc3SIngo Weinholdmain(int argc, const char *const *argv)
303338b8dc3SIngo Weinhold{
304338b8dc3SIngo Weinhold	kArgc = argc;
305338b8dc3SIngo Weinhold	kArgv = argv;
306338b8dc3SIngo Weinhold
307338b8dc3SIngo Weinhold	if (argc < 2)
308338b8dc3SIngo Weinhold		print_usage_and_exit(true);
309338b8dc3SIngo Weinhold
310338b8dc3SIngo Weinhold	// parameters
311338b8dc3SIngo Weinhold	const char **files = new const char*[argc];
312338b8dc3SIngo Weinhold	int fileCount = 0;
31304fcc147SIngo Weinhold	bool dryRun = false;
314a17d1cf4SIngo Weinhold	off_t startOffset = 0;
315338b8dc3SIngo Weinhold
316338b8dc3SIngo Weinhold	// parse arguments
317338b8dc3SIngo Weinhold	for (int argi = 1; argi < argc;) {
318338b8dc3SIngo Weinhold		const char *arg = argv[argi++];
319338b8dc3SIngo Weinhold
320338b8dc3SIngo Weinhold		if (arg[0] == '-') {
321338b8dc3SIngo Weinhold			if (strcmp(arg, "-h") == 0 || strcmp(arg, "--help") == 0) {
322338b8dc3SIngo Weinhold				print_usage_and_exit(false);
32304fcc147SIngo Weinhold			} else if (strcmp(arg, "--dry-run") == 0) {
32404fcc147SIngo Weinhold				dryRun = true;
325a17d1cf4SIngo Weinhold			} else if (strcmp(arg, "--start-offset") == 0) {
326a17d1cf4SIngo Weinhold				if (argi >= argc)
327a17d1cf4SIngo Weinhold					print_usage_and_exit(true);
328a17d1cf4SIngo Weinhold				startOffset = strtoll(argv[argi++], NULL, 0);
329338b8dc3SIngo Weinhold			} else {
330338b8dc3SIngo Weinhold				print_usage_and_exit(true);
331338b8dc3SIngo Weinhold			}
332338b8dc3SIngo Weinhold
333338b8dc3SIngo Weinhold		} else {
334338b8dc3SIngo Weinhold			files[fileCount++] = arg;
335338b8dc3SIngo Weinhold		}
336338b8dc3SIngo Weinhold	}
337338b8dc3SIngo Weinhold
338338b8dc3SIngo Weinhold	// we need at least one file
339338b8dc3SIngo Weinhold	if (fileCount == 0)
340338b8dc3SIngo Weinhold		print_usage_and_exit(true);
341338b8dc3SIngo Weinhold
34239bdbadfSIngo Weinhold	// read the boot code
34399b25014SRene Gollent	uint8 *bootCodeData = NULL;
344204dee70SIngo Weinhold#ifndef HAIKU_TARGET_PLATFORM_HAIKU
34599b25014SRene Gollent	bootCodeData = read_boot_code_data(argv[0]);
34699b25014SRene Gollent#else
34799b25014SRene Gollent	image_info info;
348c7cf1688SAxel Dörfler	if (find_own_image(&info) == B_OK)
34999b25014SRene Gollent		bootCodeData = read_boot_code_data(info.name);
35099b25014SRene Gollent#endif
35139bdbadfSIngo Weinhold	if (!bootCodeData) {
3521d467366SFredrik Modeen		fprintf(stderr, "Error: Failed to read \n");
353338b8dc3SIngo Weinhold		exit(1);
354338b8dc3SIngo Weinhold	}
355338b8dc3SIngo Weinhold
356338b8dc3SIngo Weinhold	// iterate through the files and make them bootable
35739bdbadfSIngo Weinhold	status_t error;
358338b8dc3SIngo Weinhold	for (int i = 0; i < fileCount; i++) {
359338b8dc3SIngo Weinhold		const char *fileName = files[i];
360338b8dc3SIngo Weinhold		BEntry entry;
361338b8dc3SIngo Weinhold		error = entry.SetTo(fileName, true);
362338b8dc3SIngo Weinhold		if (error != B_OK) {
363338b8dc3SIngo Weinhold			fprintf(stderr, "Error: Failed to open \"%s\": %s\n",
364338b8dc3SIngo Weinhold				fileName, strerror(error));
365338b8dc3SIngo Weinhold			exit(1);
366338b8dc3SIngo Weinhold		}
367338b8dc3SIngo Weinhold
368338b8dc3SIngo Weinhold		// get stat to check the type of the file
369338b8dc3SIngo Weinhold		struct stat st;
370338b8dc3SIngo Weinhold		error = entry.GetStat(&st);
371338b8dc3SIngo Weinhold		if (error != B_OK) {
372338b8dc3SIngo Weinhold			fprintf(stderr, "Error: Failed to stat \"%s\": %s\n",
373338b8dc3SIngo Weinhold				fileName, strerror(error));
374338b8dc3SIngo Weinhold			exit(1);
375338b8dc3SIngo Weinhold		}
376338b8dc3SIngo Weinhold
377338b8dc3SIngo Weinhold		bool noPartition = false;
37804fcc147SIngo Weinhold		int64 partitionOffset = 0;
379338b8dc3SIngo Weinhold		fs_info info;	// needs to be here (we use the device name later)
380338b8dc3SIngo Weinhold		if (S_ISDIR(st.st_mode)) {
381204dee70SIngo Weinhold			#ifdef HAIKU_TARGET_PLATFORM_HAIKU
382338b8dc3SIngo Weinhold
38304fcc147SIngo Weinhold				// a directory: get the device
38404fcc147SIngo Weinhold				error = fs_stat_dev(st.st_dev, &info);
38504fcc147SIngo Weinhold				if (error != B_OK) {
38604fcc147SIngo Weinhold					fprintf(stderr, "Error: Failed to determine device for "
38704fcc147SIngo Weinhold						"\"%s\": %s\n", fileName, strerror(error));
38804fcc147SIngo Weinhold					exit(1);
38904fcc147SIngo Weinhold				}
390338b8dc3SIngo Weinhold
39104fcc147SIngo Weinhold				fileName = info.device_name;
392338b8dc3SIngo Weinhold
393338b8dc3SIngo Weinhold			#else
394338b8dc3SIngo Weinhold
39504fcc147SIngo Weinhold				(void)info;
39604fcc147SIngo Weinhold				fprintf(stderr, "Error: Specifying directories not supported "
39704fcc147SIngo Weinhold					"on this platform!\n");
39804fcc147SIngo Weinhold				exit(1);
399c7cf1688SAxel Dörfler
400338b8dc3SIngo Weinhold			#endif
401338b8dc3SIngo Weinhold
402338b8dc3SIngo Weinhold		} else if (S_ISREG(st.st_mode)) {
403338b8dc3SIngo Weinhold			// a regular file: fine
404338b8dc3SIngo Weinhold			noPartition = true;
405338b8dc3SIngo Weinhold		} else if (S_ISCHR(st.st_mode)) {
40604fcc147SIngo Weinhold			// character special: a device or partition under BeOS
40780b2da5eSIngo Weinhold			// or under FreeBSD
408204dee70SIngo Weinhold			#if !defined(HAIKU_TARGET_PLATFORM_HAIKU) \
409204dee70SIngo Weinhold				&& !defined(HAIKU_HOST_PLATFORM_FREEBSD)
410338b8dc3SIngo Weinhold
41104fcc147SIngo Weinhold				fprintf(stderr, "Error: Character special devices not "
41204fcc147SIngo Weinhold					"supported on this platform.\n");
41304fcc147SIngo Weinhold				exit(1);
41404fcc147SIngo Weinhold
41504fcc147SIngo Weinhold			#endif
41680b2da5eSIngo Weinhold
41780b2da5eSIngo Weinhold			#ifdef HAIKU_HOST_PLATFORM_FREEBSD
41880b2da5eSIngo Weinhold
41980b2da5eSIngo Weinhold				// chop off the trailing number
42080b2da5eSIngo Weinhold				int fileNameLen = strlen(fileName);
42180b2da5eSIngo Weinhold				int baseNameLen = -1;
42280b2da5eSIngo Weinhold				for (int k = fileNameLen - 1; k >= 0; k--) {
42380b2da5eSIngo Weinhold					if (!isdigit(fileName[k])) {
42480b2da5eSIngo Weinhold						baseNameLen = k + 1;
42580b2da5eSIngo Weinhold						break;
42680b2da5eSIngo Weinhold					}
42780b2da5eSIngo Weinhold				}
428c7cf1688SAxel Dörfler
42980b2da5eSIngo Weinhold				// Remove de 's' from 'ad2s2' slice device (partition for DOS
43080b2da5eSIngo Weinhold				// users) to get 'ad2' base device
43180b2da5eSIngo Weinhold				baseNameLen--;
43280b2da5eSIngo Weinhold
43380b2da5eSIngo Weinhold				if (baseNameLen < 0) {
43480b2da5eSIngo Weinhold					// only digits?
43580b2da5eSIngo Weinhold					fprintf(stderr, "Error: Failed to get base device name.\n");
43680b2da5eSIngo Weinhold					exit(1);
43780b2da5eSIngo Weinhold				}
43880b2da5eSIngo Weinhold
43980b2da5eSIngo Weinhold				if (baseNameLen < fileNameLen) {
44080b2da5eSIngo Weinhold					// get base device name and partition index
44180b2da5eSIngo Weinhold					char baseDeviceName[B_PATH_NAME_LENGTH];
44280b2da5eSIngo Weinhold					int partitionIndex = atoi(fileName + baseNameLen + 1);
44380b2da5eSIngo Weinhold						// Don't forget the 's' of slice :)
44480b2da5eSIngo Weinhold					memcpy(baseDeviceName, fileName, baseNameLen);
44580b2da5eSIngo Weinhold					baseDeviceName[baseNameLen] = '\0';
44680b2da5eSIngo Weinhold
44780b2da5eSIngo Weinhold					// open base device
44880b2da5eSIngo Weinhold					int baseFD = open(baseDeviceName, O_RDONLY);
44980b2da5eSIngo Weinhold					if (baseFD < 0) {
45080b2da5eSIngo Weinhold						fprintf(stderr, "Error: Failed to open \"%s\": %s\n",
45180b2da5eSIngo Weinhold							baseDeviceName, strerror(errno));
45280b2da5eSIngo Weinhold						exit(1);
45380b2da5eSIngo Weinhold					}
45480b2da5eSIngo Weinhold
45580b2da5eSIngo Weinhold					// get device size
45680b2da5eSIngo Weinhold					int64 deviceSize;
45780b2da5eSIngo Weinhold					if (ioctl(baseFD, DIOCGMEDIASIZE, &deviceSize) == -1) {
45880b2da5eSIngo Weinhold						fprintf(stderr, "Error: Failed to get device geometry "
45980b2da5eSIngo Weinhold							"for \"%s\": %s\n", baseDeviceName,
46080b2da5eSIngo Weinhold							strerror(errno));
46180b2da5eSIngo Weinhold						exit(1);
46280b2da5eSIngo Weinhold					}
46380b2da5eSIngo Weinhold
46480b2da5eSIngo Weinhold					// parse the partition map
465199f3324SAxel Dörfler					// TODO: block size!
46642f25fe9SJessica Hamilton					get_partition_offset(baseFD, 0, deviceSize, 512,
46742f25fe9SJessica Hamilton						partitionIndex, baseDeviceName, partitionOffset);
46880b2da5eSIngo Weinhold				} else {
46980b2da5eSIngo Weinhold					// The given device is the base device. We'll write at
47080b2da5eSIngo Weinhold					// offset 0.
47180b2da5eSIngo Weinhold				}
47280b2da5eSIngo Weinhold
47380b2da5eSIngo Weinhold			#endif // HAIKU_HOST_PLATFORM_FREEBSD
47480b2da5eSIngo Weinhold
47504fcc147SIngo Weinhold		} else if (S_ISBLK(st.st_mode)) {
47621055357SIngo Weinhold			// block device: a device or partition under Linux or Darwin
47704fcc147SIngo Weinhold			#ifdef HAIKU_HOST_PLATFORM_LINUX
47804fcc147SIngo Weinhold
47904fcc147SIngo Weinhold				// chop off the trailing number
48004fcc147SIngo Weinhold				int fileNameLen = strlen(fileName);
48104fcc147SIngo Weinhold				int baseNameLen = -1;
48204fcc147SIngo Weinhold				for (int k = fileNameLen - 1; k >= 0; k--) {
48304fcc147SIngo Weinhold					if (!isdigit(fileName[k])) {
48404fcc147SIngo Weinhold						baseNameLen = k + 1;
48504fcc147SIngo Weinhold						break;
48604fcc147SIngo Weinhold					}
48704fcc147SIngo Weinhold				}
48804fcc147SIngo Weinhold
48904fcc147SIngo Weinhold				if (baseNameLen < 0) {
49004fcc147SIngo Weinhold					// only digits?
49104fcc147SIngo Weinhold					fprintf(stderr, "Error: Failed to get base device name.\n");
49204fcc147SIngo Weinhold					exit(1);
49304fcc147SIngo Weinhold				}
49404fcc147SIngo Weinhold
49504fcc147SIngo Weinhold				if (baseNameLen < fileNameLen) {
49604fcc147SIngo Weinhold					// get base device name and partition index
49704fcc147SIngo Weinhold					char baseDeviceName[B_PATH_NAME_LENGTH];
49804fcc147SIngo Weinhold					int partitionIndex = atoi(fileName + baseNameLen);
49904fcc147SIngo Weinhold					memcpy(baseDeviceName, fileName, baseNameLen);
50004fcc147SIngo Weinhold					baseDeviceName[baseNameLen] = '\0';
50104fcc147SIngo Weinhold
50204fcc147SIngo Weinhold					// open base device
50304fcc147SIngo Weinhold					int baseFD = open(baseDeviceName, O_RDONLY);
50404fcc147SIngo Weinhold					if (baseFD < 0) {
50504fcc147SIngo Weinhold						fprintf(stderr, "Error: Failed to open \"%s\": %s\n",
50604fcc147SIngo Weinhold							baseDeviceName, strerror(errno));
50704fcc147SIngo Weinhold						exit(1);
50804fcc147SIngo Weinhold					}
50904fcc147SIngo Weinhold
510fb7c02c2SIngo Weinhold					// get device size -- try BLKGETSIZE64, but, if it doesn't
511fb7c02c2SIngo Weinhold					// work, fall back to the obsolete HDIO_GETGEO
512fb7c02c2SIngo Weinhold					int64 deviceSize;
51304fcc147SIngo Weinhold					hd_geometry geometry;
514fb7c02c2SIngo Weinhold					if (ioctl(baseFD, BLKGETSIZE64, &deviceSize) == 0
515fb7c02c2SIngo Weinhold						&& deviceSize > 0) {
516fb7c02c2SIngo Weinhold						// looks good
517fb7c02c2SIngo Weinhold					} else if (ioctl(baseFD, HDIO_GETGEO, &geometry) == 0) {
518fb7c02c2SIngo Weinhold						deviceSize = (int64)geometry.heads * geometry.sectors
519fb7c02c2SIngo Weinhold							* geometry.cylinders * 512;
520fb7c02c2SIngo Weinhold					} else {
52104fcc147SIngo Weinhold						fprintf(stderr, "Error: Failed to get device geometry "
52204fcc147SIngo Weinhold							"for \"%s\": %s\n", baseDeviceName,
52304fcc147SIngo Weinhold							strerror(errno));
52404fcc147SIngo Weinhold						exit(1);
52504fcc147SIngo Weinhold					}
52604fcc147SIngo Weinhold
52704fcc147SIngo Weinhold					// parse the partition map
528199f3324SAxel Dörfler					// TODO: block size!
52942f25fe9SJessica Hamilton					get_partition_offset(baseFD, 0, deviceSize, 512,
53042f25fe9SJessica Hamilton						partitionIndex, baseDeviceName, partitionOffset);
53104fcc147SIngo Weinhold				} else {
53204fcc147SIngo Weinhold					// The given device is the base device. We'll write at
53304fcc147SIngo Weinhold					// offset 0.
53404fcc147SIngo Weinhold				}
535c7cf1688SAxel Dörfler
53621055357SIngo Weinhold			#elif defined(HAIKU_HOST_PLATFORM_DARWIN)
53721055357SIngo Weinhold				// chop off the trailing number
53821055357SIngo Weinhold				int fileNameLen = strlen(fileName);
53921055357SIngo Weinhold				int baseNameLen = fileNameLen - 2;
540199f3324SAxel Dörfler
54121055357SIngo Weinhold				// get base device name and partition index
54221055357SIngo Weinhold				char baseDeviceName[B_PATH_NAME_LENGTH];
54321055357SIngo Weinhold				int partitionIndex = atoi(fileName + baseNameLen + 1);
54421055357SIngo Weinhold				memcpy(baseDeviceName, fileName, baseNameLen);
54521055357SIngo Weinhold				baseDeviceName[baseNameLen] = '\0';
546199f3324SAxel Dörfler
54721055357SIngo Weinhold				// open base device
54821055357SIngo Weinhold				int baseFD = open(baseDeviceName, O_RDONLY);
54921055357SIngo Weinhold				if (baseFD < 0) {
55021055357SIngo Weinhold					fprintf(stderr, "Error: Failed to open \"%s\": %s\n",
55121055357SIngo Weinhold							baseDeviceName, strerror(errno));
55221055357SIngo Weinhold					exit(1);
55321055357SIngo Weinhold				}
554199f3324SAxel Dörfler
55521055357SIngo Weinhold				// get device size
55621055357SIngo Weinhold				int64 blockSize;
55721055357SIngo Weinhold				int64 blockCount;
55821055357SIngo Weinhold				int64 deviceSize;
55921055357SIngo Weinhold				if (ioctl(baseFD, DKIOCGETBLOCKSIZE, &blockSize) == -1) {
56021055357SIngo Weinhold					fprintf(stderr, "Error: Failed to get block size "
56121055357SIngo Weinhold							"for \"%s\": %s\n", baseDeviceName,
56221055357SIngo Weinhold							strerror(errno));
56321055357SIngo Weinhold					exit(1);
56421055357SIngo Weinhold				}
56521055357SIngo Weinhold				if (ioctl(baseFD, DKIOCGETBLOCKCOUNT, &blockCount) == -1) {
56621055357SIngo Weinhold					fprintf(stderr, "Error: Failed to get block count "
56721055357SIngo Weinhold							"for \"%s\": %s\n", baseDeviceName,
56821055357SIngo Weinhold							strerror(errno));
56921055357SIngo Weinhold					exit(1);
57021055357SIngo Weinhold				}
57104fcc147SIngo Weinhold
57221055357SIngo Weinhold				deviceSize = blockSize * blockCount;
573199f3324SAxel Dörfler
57421055357SIngo Weinhold				// parse the partition map
57542f25fe9SJessica Hamilton				get_partition_offset(baseFD, 0, deviceSize, 512,
57642f25fe9SJessica Hamilton						partitionIndex, baseDeviceName, partitionOffset);
57721055357SIngo Weinhold			#else
5786fd31accSIngo Weinhold			// partitions are block devices under Haiku, but not under BeOS
579204dee70SIngo Weinhold			#ifdef HAIKU_TARGET_PLATFORM_HAIKU
58004fcc147SIngo Weinhold				fprintf(stderr, "Error: Block devices not supported on this "
58104fcc147SIngo Weinhold					"platform!\n");
58204fcc147SIngo Weinhold				exit(1);
583204dee70SIngo Weinhold			#endif	// HAIKU_TARGET_PLATFORM_HAIKU
584338b8dc3SIngo Weinhold
585338b8dc3SIngo Weinhold			#endif
586338b8dc3SIngo Weinhold		} else {
58704fcc147SIngo Weinhold			fprintf(stderr, "Error: File type of \"%s\" is not supported.\n",
588338b8dc3SIngo Weinhold				fileName);
589338b8dc3SIngo Weinhold			exit(1);
590338b8dc3SIngo Weinhold		}
591338b8dc3SIngo Weinhold
592338b8dc3SIngo Weinhold		// open the file
593338b8dc3SIngo Weinhold		int fd = open(fileName, O_RDWR);
594338b8dc3SIngo Weinhold		if (fd < 0) {
595338b8dc3SIngo Weinhold			fprintf(stderr, "Error: Failed to open \"%s\": %s\n", fileName,
596338b8dc3SIngo Weinhold				strerror(errno));
597338b8dc3SIngo Weinhold			exit(1);
598338b8dc3SIngo Weinhold		}
599338b8dc3SIngo Weinhold
600204dee70SIngo Weinhold		#ifdef HAIKU_TARGET_PLATFORM_HAIKU
601338b8dc3SIngo Weinhold
60204fcc147SIngo Weinhold			// get a partition info
603c7cf1688SAxel Dörfler			if (!noPartition
6045d54b6c4SJérôme Duval				&& strlen(fileName) >= 3
6055d54b6c4SJérôme Duval				&& strncmp("raw", fileName + strlen(fileName) - 3, 3)) {
60604fcc147SIngo Weinhold				partition_info partitionInfo;
6076fd31accSIngo Weinhold				if (ioctl(fd, B_GET_PARTITION_INFO, &partitionInfo,
6086fd31accSIngo Weinhold						sizeof(partitionInfo)) == 0) {
609361a19cdSAxel Dörfler					partitionOffset = partitionInfo.offset;
61004fcc147SIngo Weinhold				} else {
61176a93187SJérôme Duval					fprintf(stderr, "Error: Failed to get partition info: %s\n",
61204fcc147SIngo Weinhold						strerror(errno));
61304fcc147SIngo Weinhold					exit(1);
61404fcc147SIngo Weinhold				}
61504fcc147SIngo Weinhold			}
616338b8dc3SIngo Weinhold
617f7989c02SMurai Takashi		#endif	// HAIKU_TARGET_PLATFORM_HAIKU
618338b8dc3SIngo Weinhold
61904fcc147SIngo Weinhold		// adjust the partition offset in the boot code data
62004fcc147SIngo Weinhold		// hard coded sector size: 512 bytes
621338b8dc3SIngo Weinhold		*(uint32*)(bootCodeData + kPartitionOffsetOffset)
62204fcc147SIngo Weinhold			= B_HOST_TO_LENDIAN_INT32((uint32)(partitionOffset / 512));
623338b8dc3SIngo Weinhold
624338b8dc3SIngo Weinhold		// write the boot code
625cf844822SIngo Weinhold		printf("Writing boot code to \"%s\" (partition offset: %" B_PRId64
626cf844822SIngo Weinhold			" bytes, start offset = %" B_PRIdOFF ") "
62721055357SIngo Weinhold			"...\n", fileName, partitionOffset, startOffset);
628338b8dc3SIngo Weinhold
629a17d1cf4SIngo Weinhold		write_boot_code_part(fileName, fd, startOffset, bootCodeData, 0,
63004fcc147SIngo Weinhold			kFirstBootCodePartSize, dryRun);
631a17d1cf4SIngo Weinhold		write_boot_code_part(fileName, fd, startOffset, bootCodeData,
632c7cf1688SAxel Dörfler			kSecondBootCodePartOffset, kSecondBootCodePartSize,
633a17d1cf4SIngo Weinhold			dryRun);
634338b8dc3SIngo Weinhold
635204dee70SIngo Weinhold#ifdef HAIKU_TARGET_PLATFORM_HAIKU
636c7cf1688SAxel Dörfler		// check if this partition is mounted
637c7cf1688SAxel Dörfler		BDiskDeviceRoster roster;
638c7cf1688SAxel Dörfler		BPartition* partition;
639c7cf1688SAxel Dörfler		BDiskDevice device;
640c7cf1688SAxel Dörfler		status_t status = roster.GetPartitionForPath(fileName, &device,
641c7cf1688SAxel Dörfler			&partition);
642c7cf1688SAxel Dörfler		if (status != B_OK) {
643c7cf1688SAxel Dörfler			status = roster.GetFileDeviceForPath(fileName, &device);
644c7cf1688SAxel Dörfler			if (status == B_OK)
645c7cf1688SAxel Dörfler				partition = &device;
646c7cf1688SAxel Dörfler		}
647c7cf1688SAxel Dörfler		if (status == B_OK && partition->IsMounted() && !dryRun) {
648c7cf1688SAxel Dörfler			// This partition is mounted, we need to tell BFS to update its
649c7cf1688SAxel Dörfler			// boot block (we are using part of the same logical block).
650c7cf1688SAxel Dörfler			BPath path;
651c7cf1688SAxel Dörfler			status = partition->GetMountPoint(&path);
652c7cf1688SAxel Dörfler			if (status == B_OK) {
653c7cf1688SAxel Dörfler				update_boot_block update;
654c7cf1688SAxel Dörfler				update.offset = kSecondBootCodePartOffset - 512;
655c7cf1688SAxel Dörfler				update.data = bootCodeData + kSecondBootCodePartOffset;
656c7cf1688SAxel Dörfler				update.length = kSecondBootCodePartSize;
657c7cf1688SAxel Dörfler
658c7cf1688SAxel Dörfler				int mountFD = open(path.Path(), O_RDONLY);
659c7cf1688SAxel Dörfler				if (ioctl(mountFD, BFS_IOCTL_UPDATE_BOOT_BLOCK, &update,
660c7cf1688SAxel Dörfler						sizeof(update_boot_block)) != 0) {
661c7cf1688SAxel Dörfler					fprintf(stderr, "Could not update BFS boot block: %s\n",
662c7cf1688SAxel Dörfler						strerror(errno));
663c7cf1688SAxel Dörfler				}
664c7cf1688SAxel Dörfler				close(mountFD);
665c7cf1688SAxel Dörfler			} else {
666c7cf1688SAxel Dörfler				fprintf(stderr, "Could not update BFS boot code while the "
6671d467366SFredrik Modeen					"partition is mounted!\n");
668c7cf1688SAxel Dörfler			}
669c7cf1688SAxel Dörfler		}
670204dee70SIngo Weinhold#endif	// HAIKU_TARGET_PLATFORM_HAIKU
671c7cf1688SAxel Dörfler
672338b8dc3SIngo Weinhold		close(fd);
673338b8dc3SIngo Weinhold	}
674338b8dc3SIngo Weinhold
675338b8dc3SIngo Weinhold	return 0;
676338b8dc3SIngo Weinhold}
677