* Small fixes.

* Added --dry-run option for paranoid ones like me.
* Added support for making partition devices bootable under Linux (x86, BIOS).
  
When specifying respective values for HAIKU_IMAGE_{DIR,NAME} ("/dev" and
e.g. "sda7") a "jam haiku-image" will now replace the contents of your
favorite partition with a fresh Haiku installation. BE WARNED: This is nothing
for the faint of heart and I don't guarantee that my implementation is bug-free
and won't mangle the contents of your hard disk even if you use it correctly.

That being said, note that you'll probably have to run the "jam haiku-image"
as root, if you want to access the partition devices, which is a bit annoying.
Furthermore, if the build_haiku_image script fails for any reason, jam tends
to remove the image file, which in this case would be a partition device node.
The mknod command will be your friend in this case.



git-svn-id: file:///srv/svn/repos/haiku/haiku/trunk@16148 a95241bf-73f2-0310-859d-f6bbb57e9c96
This commit is contained in:
Ingo Weinhold 2006-01-30 01:50:50 +00:00
parent deeb2f399a
commit 04fcc147ca
2 changed files with 172 additions and 41 deletions

View File

@ -1,5 +1,5 @@
/*
* Copyright 2005, Ingo Weinhold, bonefish@users.sf.net.
* Copyright 2005-2006, Ingo Weinhold, bonefish@users.sf.net.
* Distributed under the terms of the MIT License.
*/
@ -19,6 +19,17 @@
#include <Resources.h>
#include <TypeConstants.h>
// Linux support
#ifdef HAIKU_HOST_PLATFORM_LINUX
# include <ctype.h>
# include <linux/hdreg.h>
# include <sys/ioctl.h>
# include "PartitionMap.h"
# include "PartitionMapParser.h"
#endif // HAIKU_HOST_PLATFORM_LINUX
static const char *kCommandName = "makebootable";
static const int kBootCodeSize = 1024;
@ -45,6 +56,7 @@ const char *kUsage =
"\n"
"Options:\n"
" -h, --help - Print this help text and exit.\n"
" --dry-run - Do everything but actually writing the boot block to disk.\n"
"\n"
"[compatibility]\n"
" -alert - Compatibility option. Ignored.\n"
@ -84,15 +96,20 @@ print_usage_and_exit(bool error)
// write_boot_code_part
static void
write_boot_code_part(const char *fileName, int fd, const uint8 *bootCodeData,
int offset, int size)
int offset, int size, bool dryRun)
{
printf("writing %d bytes at offset %d\n", size, offset);
ssize_t bytesWritten = write_pos(fd, offset, bootCodeData + offset, size);
printf("writing %d bytes at offset %d%s\n", size, offset,
(dryRun ? " (dry run)" : ""));
if (!dryRun) {
ssize_t bytesWritten = write_pos(fd, offset, bootCodeData + offset,
size);
if (bytesWritten != size) {
fprintf(stderr, "Error: Failed to write to \"%s\": %s\n", fileName,
strerror(bytesWritten < 0 ? errno : B_ERROR));
}
}
}
// main
int
@ -107,6 +124,7 @@ main(int argc, const char *const *argv)
// parameters
const char **files = new const char*[argc];
int fileCount = 0;
bool dryRun = false;
// parse arguments
for (int argi = 1; argi < argc;) {
@ -115,12 +133,14 @@ main(int argc, const char *const *argv)
if (arg[0] == '-') {
if (strcmp(arg, "-h") == 0 || strcmp(arg, "--help") == 0) {
print_usage_and_exit(false);
} else if (strcmp(arg, "--dry-run") == 0) {
dryRun = true;
} else if (strcmp(arg, "-alert") == 0) {
// ignore
} else if (strcmp(arg, "-full") == 0) {
// ignore
} else if (strcmp(arg, "-safe") == 0) {
fprintf(stderr, "Error: Sorry, BeOS R3 isnt't supported!\n");
fprintf(stderr, "Error: Sorry, BeOS R3 isn't supported!\n");
exit(1);
} else {
print_usage_and_exit(true);
@ -166,7 +186,7 @@ main(int argc, const char *const *argv)
if (resourceSize != (size_t)kBootCodeSize) {
fprintf(stderr,
"Error: Something is fishy with my resources! The boot code "
"doesn't have the correct size\n");
"doesn't have the correct size.\n");
exit(1);
}
@ -195,6 +215,7 @@ main(int argc, const char *const *argv)
}
bool noPartition = false;
int64 partitionOffset = 0;
fs_info info; // needs to be here (we use the device name later)
if (S_ISDIR(st.st_mode)) {
#ifdef __BEOS__
@ -212,8 +233,8 @@ main(int argc, const char *const *argv)
#else
(void)info;
fprintf(stderr, "Error: Only image files are supported on this "
"platform!\n");
fprintf(stderr, "Error: Specifying directories not supported "
"on this platform!\n");
exit(1);
#endif
@ -222,16 +243,103 @@ main(int argc, const char *const *argv)
// a regular file: fine
noPartition = true;
} else if (S_ISCHR(st.st_mode)) {
// a device or partition
// character special: a device or partition under BeOS
#ifndef __BEOS__
fprintf(stderr, "Error: Only image files are supported on this "
fprintf(stderr, "Error: Character special devices not "
"supported on this platform.\n");
exit(1);
#endif
} else if (S_ISBLK(st.st_mode)) {
// block device: a device or partition under Linux
#ifdef HAIKU_HOST_PLATFORM_LINUX
// chop off the trailing number
int fileNameLen = strlen(fileName);
int baseNameLen = -1;
for (int k = fileNameLen - 1; k >= 0; k--) {
if (!isdigit(fileName[k])) {
baseNameLen = k + 1;
break;
}
}
if (baseNameLen < 0) {
// only digits?
fprintf(stderr, "Error: Failed to get base device name.\n");
exit(1);
}
if (baseNameLen < fileNameLen) {
// get base device name and partition index
char baseDeviceName[B_PATH_NAME_LENGTH];
int partitionIndex = atoi(fileName + baseNameLen);
memcpy(baseDeviceName, fileName, baseNameLen);
baseDeviceName[baseNameLen] = '\0';
// open base device
int baseFD = open(baseDeviceName, O_RDONLY);
if (baseFD < 0) {
fprintf(stderr, "Error: Failed to open \"%s\": %s\n",
baseDeviceName, strerror(errno));
exit(1);
}
// get device geometry
hd_geometry geometry;
if (ioctl(baseFD, HDIO_GETGEO, &geometry) < 0) {
fprintf(stderr, "Error: Failed to get device geometry "
"for \"%s\": %s\n", baseDeviceName,
strerror(errno));
exit(1);
}
int64 deviceSize = (int64)geometry.heads * geometry.sectors
* geometry.cylinders * 512;
// parse the partition map
PartitionMapParser parser(baseFD, 0, deviceSize, 512);
PartitionMap map;
error = parser.Parse(NULL, &map);
if (error != B_OK) {
fprintf(stderr, "Error: Parsing partition table on "
"device \"%s\" failed: %s\n", baseDeviceName,
strerror(error));
exit(1);
}
close(baseFD);
// check the partition we are supposed to write at
Partition *partition = map.PartitionAt(partitionIndex - 1);
if (!partition || partition->IsEmpty()) {
fprintf(stderr, "Error: Invalid partition index %d.\n",
partitionIndex);
exit(1);
}
if (partition->IsExtended()) {
fprintf(stderr, "Error: Partition %d is an extended "
"partition.\n", partitionIndex);
exit(1);
}
partitionOffset = partition->Offset();
} else {
// The given device is the base device. We'll write at
// offset 0.
}
#else // !HAIKU_HOST_PLATFORM_LINUX
fprintf(stderr, "Error: Block devices not supported on this "
"platform!\n");
exit(1);
#endif
} else {
fprintf(stderr, "Error: File type of \"%s\" is not unsupported\n",
fprintf(stderr, "Error: File type of \"%s\" is not supported.\n",
fileName);
exit(1);
}
@ -244,30 +352,36 @@ main(int argc, const char *const *argv)
exit(1);
}
// get a partition info
int64 partitionOffset = 0;
#ifdef __BEOS__
// get a partition info
if (!noPartition) {
partition_info partitionInfo;
if (ioctl(fd, B_GET_PARTITION_INFO, &partitionInfo) == 0) {
// hard coded sector size: 512 bytes
partitionOffset = partitionInfo.offset / 512;
} else {
fprintf(stderr, "Error: Failed to get partition info: %s",
strerror(errno));
exit(1);
}
}
#endif // __BEOS__
// adjust the partition offset in the boot code data
// hard coded sector size: 512 bytes
*(uint32*)(bootCodeData + kPartitionOffsetOffset)
= B_HOST_TO_LENDIAN_INT32((uint32)partitionOffset);
= B_HOST_TO_LENDIAN_INT32((uint32)(partitionOffset / 512));
// write the boot code
printf("Writing boot code to \"%s\" ...\n", fileName);
printf("Writing boot code to \"%s\" (partition offset: %lld bytes) "
"...\n", fileName, partitionOffset);
write_boot_code_part(fileName, fd, bootCodeData, 0,
kFirstBootCodePartSize);
kFirstBootCodePartSize, dryRun);
write_boot_code_part(fileName, fd, bootCodeData,
kSecondBootcodePartOffset, kSecondBootcodePartSize);
kSecondBootcodePartOffset, kSecondBootcodePartSize, dryRun);
close(fd);
}

View File

@ -1,10 +1,27 @@
SubDir HAIKU_TOP src tools makebootable platform bios_ia32 ;
SEARCH_SOURCE += [ FDirName $(HAIKU_TOP) src bin makebootable platform bios_ia32 ] ;
UsePrivateHeaders storage ;
SEARCH_SOURCE
+= [ FDirName $(HAIKU_TOP) src bin makebootable platform bios_ia32 ] ;
USES_BE_API on <build>makebootable = true ;
local hostPlatformSources ;
if $(HOST_PLATFORM) = linux {
hostPlatformSources = PartitionMap.cpp PartitionMapParser.cpp ;
SEARCH_SOURCE += [ FDirName $(HAIKU_TOP) src add-ons kernel
partitioning_systems intel ] ;
DEFINES += _USER_MODE ;
}
# write the stage 1 boot loader into the makebootable resources
AddFileDataResource <build>makebootable : RAWT:666:BootCode : stage1.bin ;
BuildPlatformMain <build>makebootable : makebootable.cpp : $(HOST_LIBBE) ;
BuildPlatformMain <build>makebootable :
makebootable.cpp
$(hostPlatformSources)
: $(HOST_LIBBE)
;