* 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:
parent
deeb2f399a
commit
04fcc147ca
|
@ -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.
|
* Distributed under the terms of the MIT License.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
@ -19,6 +19,17 @@
|
||||||
#include <Resources.h>
|
#include <Resources.h>
|
||||||
#include <TypeConstants.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 char *kCommandName = "makebootable";
|
||||||
|
|
||||||
static const int kBootCodeSize = 1024;
|
static const int kBootCodeSize = 1024;
|
||||||
|
@ -45,6 +56,7 @@ const char *kUsage =
|
||||||
"\n"
|
"\n"
|
||||||
"Options:\n"
|
"Options:\n"
|
||||||
" -h, --help - Print this help text and exit.\n"
|
" -h, --help - Print this help text and exit.\n"
|
||||||
|
" --dry-run - Do everything but actually writing the boot block to disk.\n"
|
||||||
"\n"
|
"\n"
|
||||||
"[compatibility]\n"
|
"[compatibility]\n"
|
||||||
" -alert - Compatibility option. Ignored.\n"
|
" -alert - Compatibility option. Ignored.\n"
|
||||||
|
@ -84,13 +96,18 @@ print_usage_and_exit(bool error)
|
||||||
// write_boot_code_part
|
// write_boot_code_part
|
||||||
static void
|
static void
|
||||||
write_boot_code_part(const char *fileName, int fd, const uint8 *bootCodeData,
|
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);
|
printf("writing %d bytes at offset %d%s\n", size, offset,
|
||||||
ssize_t bytesWritten = write_pos(fd, offset, bootCodeData + offset, size);
|
(dryRun ? " (dry run)" : ""));
|
||||||
if (bytesWritten != size) {
|
|
||||||
fprintf(stderr, "Error: Failed to write to \"%s\": %s\n", fileName,
|
if (!dryRun) {
|
||||||
strerror(bytesWritten < 0 ? errno : B_ERROR));
|
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));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -107,6 +124,7 @@ main(int argc, const char *const *argv)
|
||||||
// parameters
|
// parameters
|
||||||
const char **files = new const char*[argc];
|
const char **files = new const char*[argc];
|
||||||
int fileCount = 0;
|
int fileCount = 0;
|
||||||
|
bool dryRun = false;
|
||||||
|
|
||||||
// parse arguments
|
// parse arguments
|
||||||
for (int argi = 1; argi < argc;) {
|
for (int argi = 1; argi < argc;) {
|
||||||
|
@ -115,12 +133,14 @@ main(int argc, const char *const *argv)
|
||||||
if (arg[0] == '-') {
|
if (arg[0] == '-') {
|
||||||
if (strcmp(arg, "-h") == 0 || strcmp(arg, "--help") == 0) {
|
if (strcmp(arg, "-h") == 0 || strcmp(arg, "--help") == 0) {
|
||||||
print_usage_and_exit(false);
|
print_usage_and_exit(false);
|
||||||
|
} else if (strcmp(arg, "--dry-run") == 0) {
|
||||||
|
dryRun = true;
|
||||||
} else if (strcmp(arg, "-alert") == 0) {
|
} else if (strcmp(arg, "-alert") == 0) {
|
||||||
// ignore
|
// ignore
|
||||||
} else if (strcmp(arg, "-full") == 0) {
|
} else if (strcmp(arg, "-full") == 0) {
|
||||||
// ignore
|
// ignore
|
||||||
} else if (strcmp(arg, "-safe") == 0) {
|
} 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);
|
exit(1);
|
||||||
} else {
|
} else {
|
||||||
print_usage_and_exit(true);
|
print_usage_and_exit(true);
|
||||||
|
@ -166,7 +186,7 @@ main(int argc, const char *const *argv)
|
||||||
if (resourceSize != (size_t)kBootCodeSize) {
|
if (resourceSize != (size_t)kBootCodeSize) {
|
||||||
fprintf(stderr,
|
fprintf(stderr,
|
||||||
"Error: Something is fishy with my resources! The boot code "
|
"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);
|
exit(1);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -195,26 +215,27 @@ main(int argc, const char *const *argv)
|
||||||
}
|
}
|
||||||
|
|
||||||
bool noPartition = false;
|
bool noPartition = false;
|
||||||
|
int64 partitionOffset = 0;
|
||||||
fs_info info; // needs to be here (we use the device name later)
|
fs_info info; // needs to be here (we use the device name later)
|
||||||
if (S_ISDIR(st.st_mode)) {
|
if (S_ISDIR(st.st_mode)) {
|
||||||
#ifdef __BEOS__
|
#ifdef __BEOS__
|
||||||
|
|
||||||
// a directory: get the device
|
// a directory: get the device
|
||||||
error = fs_stat_dev(st.st_dev, &info);
|
error = fs_stat_dev(st.st_dev, &info);
|
||||||
if (error != B_OK) {
|
if (error != B_OK) {
|
||||||
fprintf(stderr, "Error: Failed to determine device for "
|
fprintf(stderr, "Error: Failed to determine device for "
|
||||||
"\"%s\": %s\n", fileName, strerror(error));
|
"\"%s\": %s\n", fileName, strerror(error));
|
||||||
exit(1);
|
exit(1);
|
||||||
}
|
}
|
||||||
|
|
||||||
fileName = info.device_name;
|
fileName = info.device_name;
|
||||||
|
|
||||||
#else
|
#else
|
||||||
|
|
||||||
(void)info;
|
(void)info;
|
||||||
fprintf(stderr, "Error: Only image files are supported on this "
|
fprintf(stderr, "Error: Specifying directories not supported "
|
||||||
"platform!\n");
|
"on this platform!\n");
|
||||||
exit(1);
|
exit(1);
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
@ -222,16 +243,103 @@ main(int argc, const char *const *argv)
|
||||||
// a regular file: fine
|
// a regular file: fine
|
||||||
noPartition = true;
|
noPartition = true;
|
||||||
} else if (S_ISCHR(st.st_mode)) {
|
} else if (S_ISCHR(st.st_mode)) {
|
||||||
// a device or partition
|
// character special: a device or partition under BeOS
|
||||||
#ifndef __BEOS__
|
#ifndef __BEOS__
|
||||||
|
|
||||||
fprintf(stderr, "Error: Only image files are supported on this "
|
fprintf(stderr, "Error: Character special devices not "
|
||||||
"platform!\n");
|
"supported on this platform.\n");
|
||||||
exit(1);
|
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
|
#endif
|
||||||
} else {
|
} else {
|
||||||
fprintf(stderr, "Error: File type of \"%s\" is not unsupported\n",
|
fprintf(stderr, "Error: File type of \"%s\" is not supported.\n",
|
||||||
fileName);
|
fileName);
|
||||||
exit(1);
|
exit(1);
|
||||||
}
|
}
|
||||||
|
@ -244,30 +352,36 @@ main(int argc, const char *const *argv)
|
||||||
exit(1);
|
exit(1);
|
||||||
}
|
}
|
||||||
|
|
||||||
// get a partition info
|
|
||||||
int64 partitionOffset = 0;
|
|
||||||
|
|
||||||
#ifdef __BEOS__
|
#ifdef __BEOS__
|
||||||
|
|
||||||
partition_info partitionInfo;
|
// get a partition info
|
||||||
if (ioctl(fd, B_GET_PARTITION_INFO, &partitionInfo) == 0) {
|
if (!noPartition) {
|
||||||
// hard coded sector size: 512 bytes
|
partition_info partitionInfo;
|
||||||
partitionOffset = partitionInfo.offset / 512;
|
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__
|
#endif // __BEOS__
|
||||||
|
|
||||||
// adjust the partition offset in the boot code data
|
// adjust the partition offset in the boot code data
|
||||||
|
// hard coded sector size: 512 bytes
|
||||||
*(uint32*)(bootCodeData + kPartitionOffsetOffset)
|
*(uint32*)(bootCodeData + kPartitionOffsetOffset)
|
||||||
= B_HOST_TO_LENDIAN_INT32((uint32)partitionOffset);
|
= B_HOST_TO_LENDIAN_INT32((uint32)(partitionOffset / 512));
|
||||||
|
|
||||||
// write the boot code
|
// 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,
|
write_boot_code_part(fileName, fd, bootCodeData, 0,
|
||||||
kFirstBootCodePartSize);
|
kFirstBootCodePartSize, dryRun);
|
||||||
write_boot_code_part(fileName, fd, bootCodeData,
|
write_boot_code_part(fileName, fd, bootCodeData,
|
||||||
kSecondBootcodePartOffset, kSecondBootcodePartSize);
|
kSecondBootcodePartOffset, kSecondBootcodePartSize, dryRun);
|
||||||
|
|
||||||
close(fd);
|
close(fd);
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,10 +1,27 @@
|
||||||
SubDir HAIKU_TOP src tools makebootable platform bios_ia32 ;
|
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 ;
|
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
|
# write the stage 1 boot loader into the makebootable resources
|
||||||
AddFileDataResource <build>makebootable : RAWT:666:BootCode : stage1.bin ;
|
AddFileDataResource <build>makebootable : RAWT:666:BootCode : stage1.bin ;
|
||||||
|
|
||||||
BuildPlatformMain <build>makebootable : makebootable.cpp : $(HOST_LIBBE) ;
|
BuildPlatformMain <build>makebootable :
|
||||||
|
makebootable.cpp
|
||||||
|
$(hostPlatformSources)
|
||||||
|
: $(HOST_LIBBE)
|
||||||
|
;
|
||||||
|
|
Loading…
Reference in New Issue