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