1139749Simp/*
2122526Ssimokawa * Copyright 2005-2009, Ingo Weinhold, ingo_weinhold@gmx.de.
3122526Ssimokawa * Distributed under the terms of the MIT License.
4103285Sikob */
5103285Sikob
6103285Sikob
7103285Sikob#include <errno.h>
8103285Sikob#include <fcntl.h>
9103285Sikob#include <stdio.h>
10103285Sikob#include <stdlib.h>
11103285Sikob#include <string.h>
12103285Sikob#include <unistd.h>
13103285Sikob#include <sys/stat.h>
14103285Sikob
15103285Sikob#include <ByteOrder.h>
16103285Sikob#include <Drivers.h>
17103285Sikob#include <Entry.h>
18103285Sikob#include <File.h>
19103285Sikob#include <fs_info.h>
20103285Sikob#include <Resources.h>
21103285Sikob#include <TypeConstants.h>
22103285Sikob
23103285Sikob// Linux and FreeBSD support
24103285Sikob#ifdef HAIKU_HOST_PLATFORM_LINUX
25103285Sikob#	include <ctype.h>
26103285Sikob#	include <linux/fs.h>
27103285Sikob#	include <linux/hdreg.h>
28103285Sikob#	include <sys/ioctl.h>
29103285Sikob
30103285Sikob#	define USE_PARTITION_MAP 1
31103285Sikob#elif HAIKU_HOST_PLATFORM_FREEBSD
32103285Sikob#	include <ctype.h>
33103285Sikob#	include <sys/disklabel.h>
34103285Sikob#	include <sys/disk.h>
35103285Sikob#	include <sys/ioctl.h>
36103285Sikob
37103285Sikob#	define USE_PARTITION_MAP 1
38103285Sikob#elif HAIKU_HOST_PLATFORM_DARWIN
39103285Sikob#	include <ctype.h>
40103285Sikob#	include <sys/disk.h>
41103285Sikob#	include <sys/ioctl.h>
42127468Ssimokawa
43103285Sikob#	define USE_PARTITION_MAP 1
44103285Sikob#endif
45103285Sikob
46127468Ssimokawa#ifdef __HAIKU__
47117126Sscottl#	include <image.h>
48117126Sscottl
49117732Ssimokawa#	include <DiskDevice.h>
50103285Sikob#	include <DiskDeviceRoster.h>
51127468Ssimokawa#	include <Partition.h>
52112136Ssimokawa#	include <Path.h>
53112136Ssimokawa
54103285Sikob#	include "bfs_control.h"
55127468Ssimokawa#endif
56127468Ssimokawa
57127468Ssimokawa#if USE_PARTITION_MAP
58127468Ssimokawa#	include "PartitionMap.h"
59127468Ssimokawa#	include "PartitionMapParser.h"
60127468Ssimokawa#endif
61127468Ssimokawa
62127468Ssimokawa
63127468Ssimokawastatic const char *kCommandName = "makebootable";
64127468Ssimokawa
65127468Ssimokawastatic const int kBootCodeSize				= 1024;
66127468Ssimokawastatic const int kFirstBootCodePartSize		= 512;
67127468Ssimokawastatic const int kSecondBootCodePartOffset	= 676;
68127468Ssimokawastatic const int kSecondBootCodePartSize	= kBootCodeSize
69127468Ssimokawa												- kSecondBootCodePartOffset;
70103285Sikobstatic const int kPartitionOffsetOffset		= 506;
71103285Sikob
72103285Sikobstatic int kArgc;
73103285Sikobstatic const char *const *kArgv;
74103285Sikob
75103285Sikob// usage
76103285Sikobconst char *kUsage =
77103285Sikob"Usage: %s [ options ] <file> ...\n"
78103285Sikob"\n"
79103285Sikob"Makes the specified BFS partitions/devices bootable by writing boot code\n"
80113584Ssimokawa"into the first two sectors. It doesn't mark the partition(s) active.\n"
81103285Sikob"\n"
82120660Ssimokawa"If a given <file> refers to a directory, the partition/device on which the\n"
83127468Ssimokawa"directory resides will be made bootable. If it refers to a regular file,\n"
84103285Sikob"the file is considered a disk image and the boot code will be written to\n"
85103285Sikob"it.\n"
86103285Sikob"\n"
87103285Sikob"Options:\n"
88111615Ssimokawa"  -h, --help    - Print this help text and exit.\n"
89121185Ssimokawa"  --dry-run     - Do everything but actually writing the boot block to disk.\n"
90121185Ssimokawa"\n"
91121185Ssimokawa"[compatibility]\n"
92121185Ssimokawa"  -alert        - Compatibility option. Ignored.\n"
93121185Ssimokawa"  -full         - Compatibility option. Ignored.\n"
94167622Ssimokawa"  -safe         - Compatibility option. Fail when specified.\n"
95113584Ssimokawa;
96113584Ssimokawa
97113584Ssimokawa
98103285Sikob// print_usage
99113584Ssimokawastatic void
100111615Ssimokawaprint_usage(bool error)
101111615Ssimokawa{
102111615Ssimokawa	// get command name
103111615Ssimokawa	const char *commandName = NULL;
104130532Sdfr	if (kArgc > 0) {
105111615Ssimokawa		if (const char *lastSlash = strchr(kArgv[0], '/'))
106111615Ssimokawa			commandName = lastSlash + 1;
107120660Ssimokawa		else
108111615Ssimokawa			commandName = kArgv[0];
109111615Ssimokawa	}
110111615Ssimokawa
111103285Sikob	if (!commandName || strlen(commandName) == 0)
112120660Ssimokawa		commandName = kCommandName;
113120660Ssimokawa
114120660Ssimokawa	// print usage
115120660Ssimokawa	fprintf((error ? stderr : stdout), kUsage, commandName, commandName,
116103285Sikob		commandName);
117103285Sikob}
118120660Ssimokawa
119103285Sikob
120103285Sikob// print_usage_and_exit
121120660Ssimokawastatic void
122103285Sikobprint_usage_and_exit(bool error)
123103285Sikob{
124111203Ssimokawa	print_usage(error);
125103285Sikob	exit(error ? 1 : 0);
126124251Ssimokawa}
127111199Ssimokawa
128122387Ssimokawa
129122387Ssimokawa// read_boot_code_data
130122387Ssimokawastatic uint8 *
131127468Ssimokawaread_boot_code_data(const char* programPath)
132127468Ssimokawa{
133103285Sikob	// open our executable
134103285Sikob	BFile executableFile;
135248085Smarius	status_t error = executableFile.SetTo(programPath, B_READ_ONLY);
136248085Smarius	if (error != B_OK) {
137103285Sikob		fprintf(stderr, "Error: Failed to open my executable file (\"%s\": "
138103285Sikob			"%s\n", programPath, strerror(error));
139103285Sikob		exit(1);
140103285Sikob	}
141103285Sikob
142103285Sikob	uint8 *bootCodeData = new uint8[kBootCodeSize];
143121792Ssimokawa
144130677Ssimokawa	// open our resources
145122387Ssimokawa	BResources resources;
146122387Ssimokawa	error = resources.SetTo(&executableFile);
147122387Ssimokawa	const void *resourceData = NULL;
148122387Ssimokawa	if (error == B_OK) {
149127468Ssimokawa		// read the boot block from the resources
150127468Ssimokawa		size_t resourceSize;
151127468Ssimokawa		resourceData = resources.LoadResource(B_RAW_TYPE, 666, &resourceSize);
152127468Ssimokawa
153103285Sikob		if (resourceData && resourceSize != (size_t)kBootCodeSize) {
154122387Ssimokawa			resourceData = NULL;
155122387Ssimokawa			printf("Warning: Something is fishy with my resources! The boot "
156122387Ssimokawa				"code doesn't have the correct size. Trying the attribute "
157122387Ssimokawa				"instead ...\n");
158122387Ssimokawa		}
159127468Ssimokawa	}
160127468Ssimokawa
161122387Ssimokawa	if (resourceData) {
162103285Sikob		// found boot data in the resources
163103285Sikob		memcpy(bootCodeData, resourceData, kBootCodeSize);
164113584Ssimokawa	} else {
165113584Ssimokawa		// no boot data in the resources; try the attribute
166167622Ssimokawa		ssize_t bytesRead = executableFile.ReadAttr("BootCode", B_RAW_TYPE,
167113584Ssimokawa			0, bootCodeData, kBootCodeSize);
168167622Ssimokawa		if (bytesRead < 0) {
169113584Ssimokawa			fprintf(stderr, "Error: Failed to read boot code from resources "
170103285Sikob				"or attribute.\n");
171103285Sikob			exit(1);
172103285Sikob		}
173113584Ssimokawa		if (bytesRead != kBootCodeSize) {
174129585Sdfr			fprintf(stderr, "Error: Failed to read boot code from resources, "
175129585Sdfr				"and the boot code in the attribute has the wrong size!\n");
176120660Ssimokawa			exit(1);
177103285Sikob		}
178113584Ssimokawa	}
179103285Sikob
180103285Sikob	return bootCodeData;
181113584Ssimokawa}
182103285Sikob
183103285Sikob
184113584Ssimokawa// write_boot_code_part
185103285Sikobstatic void
186103285Sikobwrite_boot_code_part(const char *fileName, int fd, off_t imageOffset,
187103285Sikob	const uint8 *bootCodeData, int offset, int size, bool dryRun)
188114732Ssimokawa{
189110336Ssimokawa	if (!dryRun) {
190103285Sikob		ssize_t bytesWritten = write_pos(fd, imageOffset + offset,
191110336Ssimokawa			bootCodeData + offset, size);
192103285Sikob		if (bytesWritten != size) {
193103285Sikob			fprintf(stderr, "Error: Failed to write to \"%s\": %s\n", fileName,
194103285Sikob				strerror(bytesWritten < 0 ? errno : B_ERROR));
195103285Sikob		}
196103285Sikob	}
197129585Sdfr}
198114732Ssimokawa
199129585Sdfr
200129585Sdfr#ifdef __HAIKU__
201129585Sdfr
202121185Ssimokawastatic status_t
203121185Ssimokawafind_own_image(image_info *info)
204121185Ssimokawa{
205121185Ssimokawa	int32 cookie = 0;
206127468Ssimokawa	while (get_next_image_info(B_CURRENT_TEAM, &cookie, info) == B_OK) {
207127468Ssimokawa		if (((addr_t)info->text <= (addr_t)find_own_image
208127468Ssimokawa			&& (addr_t)info->text + info->text_size
209129585Sdfr				> (addr_t)find_own_image)) {
210103285Sikob			return B_OK;
211103285Sikob		}
212113584Ssimokawa	}
213113584Ssimokawa
214111615Ssimokawa	return B_NAME_NOT_FOUND;
215113584Ssimokawa}
216103285Sikob
217113584Ssimokawa#endif
218127468Ssimokawa
219103285Sikob
220103285Sikob#if USE_PARTITION_MAP
221103285Sikob
222188756Ssbrunostatic void
223103285Sikobdump_partition_map(const PartitionMap& map)
224103285Sikob{
225103285Sikob	fprintf(stderr, "partitions:\n");
226103285Sikob	int32 count = map.CountPartitions();
227103285Sikob	for (int i = 0; i < count; i++) {
228121185Ssimokawa		const Partition* partition = map.PartitionAt(i);
229103285Sikob		fprintf(stderr, "%2d: ", i);
230103285Sikob		if (partition == NULL) {
231129585Sdfr			fprintf(stderr, "<null>\n");
232111615Ssimokawa			continue;
233111615Ssimokawa		}
234111615Ssimokawa
235111615Ssimokawa		if (partition->IsEmpty()) {
236113584Ssimokawa			fprintf(stderr, "<empty>\n");
237113584Ssimokawa			continue;
238103285Sikob		}
239103285Sikob
240103285Sikob		fprintf(stderr, "offset: %16" B_PRIdOFF ", size: %16" B_PRIdOFF
241103285Sikob			", type: %x%s\n", partition->Offset(), partition->Size(),
242103285Sikob			partition->Type(), partition->IsExtended() ? " (extended)" : "");
243111615Ssimokawa	}
244103285Sikob}
245103285Sikob
246103285Sikob#endif
247122387Ssimokawa
248124145Ssimokawa
249124145Ssimokawa// main
250170374Ssimokawaint
251103285Sikobmain(int argc, const char *const *argv)
252170374Ssimokawa{
253170374Ssimokawa	kArgc = argc;
254122387Ssimokawa	kArgv = argv;
255124169Ssimokawa
256124169Ssimokawa	if (argc < 2)
257124169Ssimokawa		print_usage_and_exit(true);
258121185Ssimokawa
259124169Ssimokawa	// parameters
260121185Ssimokawa	const char **files = new const char*[argc];
261124169Ssimokawa	int fileCount = 0;
262127468Ssimokawa	bool dryRun = false;
263124169Ssimokawa	off_t startOffset = 0;
264124169Ssimokawa
265124169Ssimokawa	// parse arguments
266124169Ssimokawa	for (int argi = 1; argi < argc;) {
267170807Ssimokawa		const char *arg = argv[argi++];
268124169Ssimokawa
269124169Ssimokawa		if (arg[0] == '-') {
270124169Ssimokawa			if (strcmp(arg, "-h") == 0 || strcmp(arg, "--help") == 0) {
271124169Ssimokawa				print_usage_and_exit(false);
272121185Ssimokawa			} else if (strcmp(arg, "--dry-run") == 0) {
273121185Ssimokawa				dryRun = true;
274124169Ssimokawa			} else if (strcmp(arg, "-alert") == 0) {
275124169Ssimokawa				// ignore
276124169Ssimokawa			} else if (strcmp(arg, "-full") == 0) {
277124169Ssimokawa				// ignore
278124169Ssimokawa			} else if (strcmp(arg, "--start-offset") == 0) {
279103285Sikob				if (argi >= argc)
280249132Smav					print_usage_and_exit(true);
281103285Sikob				startOffset = strtoll(argv[argi++], NULL, 0);
282103285Sikob			} else if (strcmp(arg, "-safe") == 0) {
283103285Sikob				fprintf(stderr, "Error: Sorry, BeOS R3 isn't supported!\n");
284103285Sikob				exit(1);
285111615Ssimokawa			} else {
286111615Ssimokawa				print_usage_and_exit(true);
287103285Sikob			}
288103285Sikob
289103285Sikob		} else {
290103285Sikob			files[fileCount++] = arg;
291103285Sikob		}
292103285Sikob	}
293103285Sikob
294103285Sikob	// we need at least one file
295103285Sikob	if (fileCount == 0)
296103285Sikob		print_usage_and_exit(true);
297103285Sikob
298103285Sikob	// read the boot code
299103285Sikob	uint8 *bootCodeData = NULL;
300103285Sikob#ifndef __HAIKU__
301103285Sikob	bootCodeData = read_boot_code_data(argv[0]);
302103285Sikob#else
303103285Sikob	image_info info;
304103285Sikob	if (find_own_image(&info) == B_OK)
305103285Sikob		bootCodeData = read_boot_code_data(info.name);
306103285Sikob#endif
307103285Sikob	if (!bootCodeData) {
308103285Sikob		fprintf(stderr, "Error: Failed to read \n");
309103285Sikob		exit(1);
310103285Sikob	}
311103285Sikob
312103285Sikob	// iterate through the files and make them bootable
313103285Sikob	status_t error;
314103285Sikob	for (int i = 0; i < fileCount; i++) {
315103285Sikob		const char *fileName = files[i];
316103285Sikob		BEntry entry;
317103285Sikob		error = entry.SetTo(fileName, true);
318103285Sikob		if (error != B_OK) {
319103285Sikob			fprintf(stderr, "Error: Failed to open \"%s\": %s\n",
320103285Sikob				fileName, strerror(error));
321103285Sikob			exit(1);
322103285Sikob		}
323103285Sikob
324103285Sikob		// get stat to check the type of the file
325103285Sikob		struct stat st;
326103285Sikob		error = entry.GetStat(&st);
327103285Sikob		if (error != B_OK) {
328103285Sikob			fprintf(stderr, "Error: Failed to stat \"%s\": %s\n",
329103285Sikob				fileName, strerror(error));
330103285Sikob			exit(1);
331103285Sikob		}
332103285Sikob
333103285Sikob		bool noPartition = false;
334103285Sikob		int64 partitionOffset = 0;
335103285Sikob		fs_info info;	// needs to be here (we use the device name later)
336103285Sikob		if (S_ISDIR(st.st_mode)) {
337103285Sikob			#if defined(__BEOS__) || defined(__HAIKU__)
338103285Sikob
339188393Sfjoe				// a directory: get the device
340103285Sikob				error = fs_stat_dev(st.st_dev, &info);
341103285Sikob				if (error != B_OK) {
342103285Sikob					fprintf(stderr, "Error: Failed to determine device for "
343103285Sikob						"\"%s\": %s\n", fileName, strerror(error));
344103285Sikob					exit(1);
345103285Sikob				}
346103285Sikob
347103285Sikob				fileName = info.device_name;
348103285Sikob
349103285Sikob			#else
350103285Sikob
351103285Sikob				(void)info;
352103285Sikob				fprintf(stderr, "Error: Specifying directories not supported "
353103285Sikob					"on this platform!\n");
354103285Sikob				exit(1);
355103285Sikob
356103285Sikob			#endif
357103285Sikob
358103285Sikob		} else if (S_ISREG(st.st_mode)) {
359120660Ssimokawa			// a regular file: fine
360111615Ssimokawa			noPartition = true;
361132432Ssimokawa		} else if (S_ISCHR(st.st_mode)) {
362111615Ssimokawa			// character special: a device or partition under BeOS
363111615Ssimokawa			// or under FreeBSD
364132432Ssimokawa			#if !(defined(__BEOS__) || defined(__HAIKU__)) && !defined(HAIKU_HOST_PLATFORM_FREEBSD)
365132432Ssimokawa
366103285Sikob				fprintf(stderr, "Error: Character special devices not "
367103285Sikob					"supported on this platform.\n");
368103285Sikob				exit(1);
369188756Ssbruno
370188756Ssbruno			#endif
371188756Ssbruno
372103285Sikob			#ifdef HAIKU_HOST_PLATFORM_FREEBSD
373188756Ssbruno
374103285Sikob				// chop off the trailing number
375103285Sikob				int fileNameLen = strlen(fileName);
376103285Sikob				int baseNameLen = -1;
377103285Sikob				for (int k = fileNameLen - 1; k >= 0; k--) {
378188756Ssbruno					if (!isdigit(fileName[k])) {
379188756Ssbruno						baseNameLen = k + 1;
380188756Ssbruno						break;
381188756Ssbruno					}
382188756Ssbruno				}
383108503Ssimokawa
384108503Ssimokawa				// Remove de 's' from 'ad2s2' slice device (partition for DOS
385103285Sikob				// users) to get 'ad2' base device
386103285Sikob				baseNameLen--;
387103285Sikob
388103285Sikob				if (baseNameLen < 0) {
389188756Ssbruno					// only digits?
390188756Ssbruno					fprintf(stderr, "Error: Failed to get base device name.\n");
391188756Ssbruno					exit(1);
392188756Ssbruno				}
393188756Ssbruno
394188756Ssbruno				if (baseNameLen < fileNameLen) {
395188756Ssbruno					// get base device name and partition index
396188756Ssbruno					char baseDeviceName[B_PATH_NAME_LENGTH];
397188756Ssbruno					int partitionIndex = atoi(fileName + baseNameLen + 1);
398103285Sikob						// Don't forget the 's' of slice :)
399103285Sikob					memcpy(baseDeviceName, fileName, baseNameLen);
400110184Ssimokawa					baseDeviceName[baseNameLen] = '\0';
401110184Ssimokawa
402110184Ssimokawa					// open base device
403110184Ssimokawa					int baseFD = open(baseDeviceName, O_RDONLY);
404110184Ssimokawa					if (baseFD < 0) {
405110184Ssimokawa						fprintf(stderr, "Error: Failed to open \"%s\": %s\n",
406110184Ssimokawa							baseDeviceName, strerror(errno));
407110184Ssimokawa						exit(1);
408110184Ssimokawa					}
409110184Ssimokawa
410110184Ssimokawa					// get device size
411110184Ssimokawa					int64 deviceSize;
412110184Ssimokawa					if (ioctl(baseFD, DIOCGMEDIASIZE, &deviceSize) == -1) {
413110184Ssimokawa						fprintf(stderr, "Error: Failed to get device geometry "
414110184Ssimokawa							"for \"%s\": %s\n", baseDeviceName,
415110184Ssimokawa							strerror(errno));
416110184Ssimokawa						exit(1);
417110184Ssimokawa					}
418110184Ssimokawa
419110184Ssimokawa					// parse the partition map
420110184Ssimokawa					// TODO: block size!
421110184Ssimokawa					PartitionMapParser parser(baseFD, 0, deviceSize, 512);
422110184Ssimokawa					PartitionMap map;
423110184Ssimokawa					error = parser.Parse(NULL, &map);
424110184Ssimokawa					if (error != B_OK) {
425110184Ssimokawa						fprintf(stderr, "Error: Parsing partition table on "
426110184Ssimokawa							"device \"%s\" failed: %s\n", baseDeviceName,
427110184Ssimokawa							strerror(error));
428110184Ssimokawa						exit(1);
429110184Ssimokawa					}
430110184Ssimokawa
431110184Ssimokawa					close(baseFD);
432110184Ssimokawa
433110184Ssimokawa					// check the partition we are supposed to write at
434110184Ssimokawa					Partition *partition = map.PartitionAt(partitionIndex - 1);
435110184Ssimokawa					if (!partition || partition->IsEmpty()) {
436110184Ssimokawa						fprintf(stderr, "Error: Invalid partition index %d.\n",
437110184Ssimokawa							partitionIndex);
438110184Ssimokawa						dump_partition_map(map);
439110184Ssimokawa						exit(1);
440110184Ssimokawa					}
441110184Ssimokawa
442110184Ssimokawa					if (partition->IsExtended()) {
443110184Ssimokawa						fprintf(stderr, "Error: Partition %d is an extended "
444110184Ssimokawa							"partition.\n", partitionIndex);
445110184Ssimokawa						dump_partition_map(map);
446110184Ssimokawa						exit(1);
447110184Ssimokawa					}
448110184Ssimokawa
449110184Ssimokawa					partitionOffset = partition->Offset();
450110184Ssimokawa
451110184Ssimokawa				} else {
452121185Ssimokawa					// The given device is the base device. We'll write at
453121185Ssimokawa					// offset 0.
454103285Sikob				}
455108503Ssimokawa
456108503Ssimokawa			#endif // HAIKU_HOST_PLATFORM_FREEBSD
457121185Ssimokawa
458121185Ssimokawa		} else if (S_ISBLK(st.st_mode)) {
459121185Ssimokawa			// block device: a device or partition under Linux or Darwin
460103285Sikob			#ifdef HAIKU_HOST_PLATFORM_LINUX
461121185Ssimokawa
462114069Ssimokawa				// chop off the trailing number
463108503Ssimokawa				int fileNameLen = strlen(fileName);
464108503Ssimokawa				int baseNameLen = -1;
465108503Ssimokawa				for (int k = fileNameLen - 1; k >= 0; k--) {
466108503Ssimokawa					if (!isdigit(fileName[k])) {
467108503Ssimokawa						baseNameLen = k + 1;
468108503Ssimokawa						break;
469110839Ssimokawa					}
470108642Ssimokawa				}
471108642Ssimokawa
472108642Ssimokawa				if (baseNameLen < 0) {
473108503Ssimokawa					// only digits?
474108503Ssimokawa					fprintf(stderr, "Error: Failed to get base device name.\n");
475108503Ssimokawa					exit(1);
476108503Ssimokawa				}
477110839Ssimokawa
478121185Ssimokawa				if (baseNameLen < fileNameLen) {
479121185Ssimokawa					// get base device name and partition index
480121185Ssimokawa					char baseDeviceName[B_PATH_NAME_LENGTH];
481121185Ssimokawa					int partitionIndex = atoi(fileName + baseNameLen);
482121185Ssimokawa					memcpy(baseDeviceName, fileName, baseNameLen);
483110839Ssimokawa					baseDeviceName[baseNameLen] = '\0';
484110839Ssimokawa
485121185Ssimokawa					// open base device
486121185Ssimokawa					int baseFD = open(baseDeviceName, O_RDONLY);
487121185Ssimokawa					if (baseFD < 0) {
488121185Ssimokawa						fprintf(stderr, "Error: Failed to open \"%s\": %s\n",
489121185Ssimokawa							baseDeviceName, strerror(errno));
490121185Ssimokawa						exit(1);
491121185Ssimokawa					}
492121185Ssimokawa
493121185Ssimokawa					// get device size -- try BLKGETSIZE64, but, if it doesn't
494121185Ssimokawa					// work, fall back to the obsolete HDIO_GETGEO
495121185Ssimokawa					int64 deviceSize;
496187993Ssbruno					hd_geometry geometry;
497121185Ssimokawa					if (ioctl(baseFD, BLKGETSIZE64, &deviceSize) == 0
498103285Sikob						&& deviceSize > 0) {
499121185Ssimokawa						// looks good
500121185Ssimokawa					} else if (ioctl(baseFD, HDIO_GETGEO, &geometry) == 0) {
501121185Ssimokawa						deviceSize = (int64)geometry.heads * geometry.sectors
502121185Ssimokawa							* geometry.cylinders * 512;
503121185Ssimokawa					} else {
504121185Ssimokawa						fprintf(stderr, "Error: Failed to get device geometry "
505121185Ssimokawa							"for \"%s\": %s\n", baseDeviceName,
506121185Ssimokawa							strerror(errno));
507127468Ssimokawa						exit(1);
508121185Ssimokawa					}
509121185Ssimokawa
510121185Ssimokawa					// parse the partition map
511121185Ssimokawa					// TODO: block size!
512121185Ssimokawa					PartitionMapParser parser(baseFD, 0, deviceSize, 512);
513121185Ssimokawa					PartitionMap map;
514121185Ssimokawa					error = parser.Parse(NULL, &map);
515121185Ssimokawa					if (error != B_OK) {
516121185Ssimokawa						fprintf(stderr, "Error: Parsing partition table on "
517121185Ssimokawa							"device \"%s\" failed: %s\n", baseDeviceName,
518121185Ssimokawa							strerror(error));
519121185Ssimokawa						exit(1);
520121185Ssimokawa					}
521121185Ssimokawa
522121185Ssimokawa					close(baseFD);
523121185Ssimokawa
524121185Ssimokawa					// check the partition we are supposed to write at
525108503Ssimokawa					Partition *partition = map.PartitionAt(partitionIndex - 1);
526108503Ssimokawa					if (!partition || partition->IsEmpty()) {
527121185Ssimokawa						fprintf(stderr, "Error: Invalid partition index %d.\n",
528121185Ssimokawa							partitionIndex);
529108503Ssimokawa						dump_partition_map(map);
530108503Ssimokawa						exit(1);
531108503Ssimokawa					}
532110839Ssimokawa
533110839Ssimokawa					if (partition->IsExtended()) {
534110839Ssimokawa						fprintf(stderr, "Error: Partition %d is an extended "
535121185Ssimokawa							"partition.\n", partitionIndex);
536110839Ssimokawa						dump_partition_map(map);
537121185Ssimokawa						exit(1);
538121185Ssimokawa					}
539121185Ssimokawa
540121185Ssimokawa					partitionOffset = partition->Offset();
541121185Ssimokawa				} else {
542121185Ssimokawa					// The given device is the base device. We'll write at
543127468Ssimokawa					// offset 0.
544121185Ssimokawa				}
545121185Ssimokawa
546121185Ssimokawa			#elif defined(HAIKU_HOST_PLATFORM_DARWIN)
547121185Ssimokawa				// chop off the trailing number
548121185Ssimokawa				int fileNameLen = strlen(fileName);
549121185Ssimokawa				int baseNameLen = fileNameLen - 2;
550121185Ssimokawa
551121185Ssimokawa				// get base device name and partition index
552121185Ssimokawa				char baseDeviceName[B_PATH_NAME_LENGTH];
553188756Ssbruno				int partitionIndex = atoi(fileName + baseNameLen + 1);
554188756Ssbruno				memcpy(baseDeviceName, fileName, baseNameLen);
555188756Ssbruno				baseDeviceName[baseNameLen] = '\0';
556188756Ssbruno
557121185Ssimokawa				// open base device
558121185Ssimokawa				int baseFD = open(baseDeviceName, O_RDONLY);
559119196Ssimokawa				if (baseFD < 0) {
560113584Ssimokawa					fprintf(stderr, "Error: Failed to open \"%s\": %s\n",
561121185Ssimokawa							baseDeviceName, strerror(errno));
562121185Ssimokawa					exit(1);
563121185Ssimokawa				}
564113584Ssimokawa
565129585Sdfr				// get device size
566219543Smarius				int64 blockSize;
567219543Smarius				int64 blockCount;
568113584Ssimokawa				int64 deviceSize;
569113584Ssimokawa				if (ioctl(baseFD, DKIOCGETBLOCKSIZE, &blockSize) == -1) {
570127468Ssimokawa					fprintf(stderr, "Error: Failed to get block size "
571121185Ssimokawa							"for \"%s\": %s\n", baseDeviceName,
572121185Ssimokawa							strerror(errno));
573121185Ssimokawa					exit(1);
574113584Ssimokawa				}
575113584Ssimokawa				if (ioctl(baseFD, DKIOCGETBLOCKCOUNT, &blockCount) == -1) {
576113584Ssimokawa					fprintf(stderr, "Error: Failed to get block count "
577113584Ssimokawa							"for \"%s\": %s\n", baseDeviceName,
578113584Ssimokawa							strerror(errno));
579113584Ssimokawa					exit(1);
580113584Ssimokawa				}
581113584Ssimokawa
582113584Ssimokawa				deviceSize = blockSize * blockCount;
583113584Ssimokawa
584113584Ssimokawa				// parse the partition map
585113584Ssimokawa				PartitionMapParser parser(baseFD, 0, deviceSize, blockSize);
586113584Ssimokawa				PartitionMap map;
587113584Ssimokawa				error = parser.Parse(NULL, &map);
588113584Ssimokawa				if (error != B_OK) {
589113584Ssimokawa					fprintf(stderr, "Error: Parsing partition table on "
590113584Ssimokawa							"device \"%s\" failed: %s\n", baseDeviceName,
591121185Ssimokawa							strerror(error));
592121185Ssimokawa					exit(1);
593113584Ssimokawa				}
594113584Ssimokawa
595113584Ssimokawa				close(baseFD);
596121185Ssimokawa
597108503Ssimokawa				// check the partition we are supposed to write at
598103285Sikob				Partition *partition = map.PartitionAt(partitionIndex - 1);
599121185Ssimokawa				if (!partition || partition->IsEmpty()) {
600121185Ssimokawa					fprintf(stderr, "Error: Invalid partition index %d.\n",
601121185Ssimokawa						partitionIndex);
602121185Ssimokawa					dump_partition_map(map);
603121185Ssimokawa					exit(1);
604121185Ssimokawa				}
605121185Ssimokawa
606121185Ssimokawa				if (partition->IsExtended()) {
607121185Ssimokawa					fprintf(stderr, "Error: Partition %d is an extended "
608121185Ssimokawa						"partition.\n", partitionIndex);
609121185Ssimokawa					dump_partition_map(map);
610121185Ssimokawa					exit(1);
611121185Ssimokawa				}
612121185Ssimokawa				partitionOffset = partition->Offset();
613121185Ssimokawa			#else
614121185Ssimokawa			// partitions are block devices under Haiku, but not under BeOS
615121185Ssimokawa			#ifndef __HAIKU__
616121185Ssimokawa				fprintf(stderr, "Error: Block devices not supported on this "
617121185Ssimokawa					"platform!\n");
618121185Ssimokawa				exit(1);
619121185Ssimokawa			#endif	// __HAIKU__
620121185Ssimokawa
621121185Ssimokawa			#endif
622121185Ssimokawa		} else {
623121185Ssimokawa			fprintf(stderr, "Error: File type of \"%s\" is not supported.\n",
624121185Ssimokawa				fileName);
625121185Ssimokawa			exit(1);
626121185Ssimokawa		}
627121185Ssimokawa
628121185Ssimokawa		// open the file
629121185Ssimokawa		int fd = open(fileName, O_RDWR);
630121185Ssimokawa		if (fd < 0) {
631121185Ssimokawa			fprintf(stderr, "Error: Failed to open \"%s\": %s\n", fileName,
632121185Ssimokawa				strerror(errno));
633121185Ssimokawa			exit(1);
634121185Ssimokawa		}
635121185Ssimokawa
636121185Ssimokawa		#if (defined(__BEOS__) || defined(__HAIKU__))
637121185Ssimokawa
638121185Ssimokawa			// get a partition info
639121185Ssimokawa			if (!noPartition
640121185Ssimokawa				&& strlen(fileName) >= 3
641121185Ssimokawa				&& strncmp("raw", fileName + strlen(fileName) - 3, 3)) {
642121185Ssimokawa				partition_info partitionInfo;
643121185Ssimokawa				if (ioctl(fd, B_GET_PARTITION_INFO, &partitionInfo,
644121185Ssimokawa						sizeof(partitionInfo)) == 0) {
645121185Ssimokawa					partitionOffset = partitionInfo.offset;
646121185Ssimokawa				} else {
647121185Ssimokawa					fprintf(stderr, "Error: Failed to get partition info: %s\n",
648121185Ssimokawa						strerror(errno));
649121185Ssimokawa					exit(1);
650121185Ssimokawa				}
651121185Ssimokawa			}
652121185Ssimokawa
653121185Ssimokawa		#endif	// __BEOS__
654114069Ssimokawa
655103285Sikob		// adjust the partition offset in the boot code data
656103285Sikob		// hard coded sector size: 512 bytes
657103285Sikob		*(uint32*)(bootCodeData + kPartitionOffsetOffset)
658103285Sikob			= B_HOST_TO_LENDIAN_INT32((uint32)(partitionOffset / 512));
659103285Sikob
660103285Sikob		// write the boot code
661114069Ssimokawa		printf("Writing boot code to \"%s\" (partition offset: %" B_PRId64
662114069Ssimokawa			" bytes, start offset = %" B_PRIdOFF ") "
663103285Sikob			"...\n", fileName, partitionOffset, startOffset);
664103285Sikob
665103285Sikob		write_boot_code_part(fileName, fd, startOffset, bootCodeData, 0,
666114069Ssimokawa			kFirstBootCodePartSize, dryRun);
667114069Ssimokawa		write_boot_code_part(fileName, fd, startOffset, bootCodeData,
668114069Ssimokawa			kSecondBootCodePartOffset, kSecondBootCodePartSize,
669114069Ssimokawa			dryRun);
670114069Ssimokawa
671114069Ssimokawa#ifdef __HAIKU__
672114069Ssimokawa		// check if this partition is mounted
673114223Ssimokawa		BDiskDeviceRoster roster;
674114260Ssimokawa		BPartition* partition;
675114223Ssimokawa		BDiskDevice device;
676114223Ssimokawa		status_t status = roster.GetPartitionForPath(fileName, &device,
677114260Ssimokawa			&partition);
678114260Ssimokawa		if (status != B_OK) {
679114069Ssimokawa			status = roster.GetFileDeviceForPath(fileName, &device);
680114069Ssimokawa			if (status == B_OK)
681114069Ssimokawa				partition = &device;
682114069Ssimokawa		}
683114069Ssimokawa		if (status == B_OK && partition->IsMounted() && !dryRun) {
684114069Ssimokawa			// This partition is mounted, we need to tell BFS to update its
685114069Ssimokawa			// boot block (we are using part of the same logical block).
686114069Ssimokawa			BPath path;
687114069Ssimokawa			status = partition->GetMountPoint(&path);
688103285Sikob			if (status == B_OK) {
689111615Ssimokawa				update_boot_block update;
690103285Sikob				update.offset = kSecondBootCodePartOffset - 512;
691111615Ssimokawa				update.data = bootCodeData + kSecondBootCodePartOffset;
692103285Sikob				update.length = kSecondBootCodePartSize;
693111615Ssimokawa
694111615Ssimokawa				int mountFD = open(path.Path(), O_RDONLY);
695111615Ssimokawa				if (ioctl(mountFD, BFS_IOCTL_UPDATE_BOOT_BLOCK, &update,
696111615Ssimokawa						sizeof(update_boot_block)) != 0) {
697122387Ssimokawa					fprintf(stderr, "Could not update BFS boot block: %s\n",
698122387Ssimokawa						strerror(errno));
699122387Ssimokawa				}
700122387Ssimokawa				close(mountFD);
701122387Ssimokawa			} else {
702122387Ssimokawa				fprintf(stderr, "Could not update BFS boot code while the "
703122387Ssimokawa					"partition is mounted!\n");
704122387Ssimokawa			}
705122387Ssimokawa		}
706122387Ssimokawa#endif	// __HAIKU__
707122387Ssimokawa
708122387Ssimokawa		close(fd);
709122387Ssimokawa	}
710122387Ssimokawa
711122387Ssimokawa	return 0;
712153706Strhodes}
713153706Strhodes