* 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.
|
||||
*/
|
||||
|
||||
|
@ -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,13 +96,18 @@ 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);
|
||||
if (bytesWritten != size) {
|
||||
fprintf(stderr, "Error: Failed to write to \"%s\": %s\n", fileName,
|
||||
strerror(bytesWritten < 0 ? errno : B_ERROR));
|
||||
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));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -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,26 +215,27 @@ 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__
|
||||
|
||||
// a directory: get the device
|
||||
error = fs_stat_dev(st.st_dev, &info);
|
||||
if (error != B_OK) {
|
||||
fprintf(stderr, "Error: Failed to determine device for "
|
||||
"\"%s\": %s\n", fileName, strerror(error));
|
||||
exit(1);
|
||||
}
|
||||
// a directory: get the device
|
||||
error = fs_stat_dev(st.st_dev, &info);
|
||||
if (error != B_OK) {
|
||||
fprintf(stderr, "Error: Failed to determine device for "
|
||||
"\"%s\": %s\n", fileName, strerror(error));
|
||||
exit(1);
|
||||
}
|
||||
|
||||
fileName = info.device_name;
|
||||
fileName = info.device_name;
|
||||
|
||||
#else
|
||||
|
||||
(void)info;
|
||||
fprintf(stderr, "Error: Only image files are supported on this "
|
||||
"platform!\n");
|
||||
exit(1);
|
||||
(void)info;
|
||||
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 "
|
||||
"platform!\n");
|
||||
exit(1);
|
||||
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__
|
||||
|
||||
partition_info partitionInfo;
|
||||
if (ioctl(fd, B_GET_PARTITION_INFO, &partitionInfo) == 0) {
|
||||
// hard coded sector size: 512 bytes
|
||||
partitionOffset = partitionInfo.offset / 512;
|
||||
}
|
||||
// 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
|
||||
// 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);
|
||||
}
|
||||
|
|
|
@ -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)
|
||||
;
|
||||
|
|
Loading…
Reference in New Issue