1193323Sed/* 2193323Sed * Copyright 2005-2009, Ingo Weinhold, ingo_weinhold@gmx.de. 3193323Sed * Distributed under the terms of the MIT License. 4193323Sed */ 5193323Sed 6193323Sed 7193323Sed#include <errno.h> 8193323Sed#include <fcntl.h> 9193323Sed#include <stdio.h> 10193323Sed#include <stdlib.h> 11193323Sed#include <string.h> 12193323Sed#include <unistd.h> 13193323Sed#include <sys/stat.h> 14193323Sed 15193323Sed#include <ByteOrder.h> 16224145Sdim#include <Entry.h> 17224145Sdim#include <File.h> 18224145Sdim#include <fs_info.h> 19224145Sdim#include <Resources.h> 20224145Sdim#include <TypeConstants.h> 21224145Sdim 22224145Sdim// Linux and FreeBSD support 23193323Sed#ifdef HAIKU_HOST_PLATFORM_LINUX 24193323Sed# include <ctype.h> 25210299Sed# include <linux/fs.h> 26210299Sed# include <linux/hdreg.h> 27193323Sed# include <sys/ioctl.h> 28224145Sdim 29224145Sdim# define USE_PARTITION_MAP 1 30224145Sdim#elif HAIKU_HOST_PLATFORM_FREEBSD 31224145Sdim# include <ctype.h> 32224145Sdim# include <sys/disklabel.h> 33224145Sdim# include <sys/disk.h> 34224145Sdim# include <sys/ioctl.h> 35224145Sdim 36224145Sdim# define USE_PARTITION_MAP 1 37224145Sdim#elif HAIKU_HOST_PLATFORM_DARWIN 38224145Sdim# include <ctype.h> 39224145Sdim# include <sys/disk.h> 40224145Sdim# include <sys/ioctl.h> 41224145Sdim 42224145Sdim# define USE_PARTITION_MAP 1 43224145Sdim#endif 44224145Sdim 45224145Sdim#ifdef HAIKU_TARGET_PLATFORM_HAIKU 46224145Sdim# include <image.h> 47224145Sdim 48193323Sed# include <DiskDevice.h> 49193323Sed# include <DiskDeviceRoster.h> 50224145Sdim# include <Drivers.h> 51224145Sdim# include <Partition.h> 52224145Sdim# include <Path.h> 53224145Sdim 54224145Sdim# include "bfs_control.h" 55224145Sdim#endif 56224145Sdim 57224145Sdim#if USE_PARTITION_MAP 58224145Sdim# include "guid.h" 59224145Sdim# include "gpt_known_guids.h" 60224145Sdim# include "Header.h" 61224145Sdim# include "PartitionMap.h" 62224145Sdim# include "PartitionMapParser.h" 63224145Sdim#endif 64224145Sdim 65224145Sdim 66224145Sdimstatic const char *kCommandName = "makebootable"; 67224145Sdim 68224145Sdimstatic const int kBootCodeSize = 1024; 69224145Sdimstatic const int kFirstBootCodePartSize = 512; 70224145Sdimstatic const int kSecondBootCodePartOffset = 676; 71224145Sdimstatic const int kSecondBootCodePartSize = kBootCodeSize 72224145Sdim - kSecondBootCodePartOffset; 73224145Sdimstatic const int kPartitionOffsetOffset = 506; 74224145Sdim 75224145Sdimstatic int kArgc; 76224145Sdimstatic const char *const *kArgv; 77224145Sdim 78224145Sdim// usage 79224145Sdimconst char *kUsage = 80224145Sdim"Usage: %s [ options ] <file> ...\n" 81224145Sdim"\n" 82224145Sdim"Makes the specified BFS partitions/devices bootable by writing boot code\n" 83224145Sdim"into the first two sectors. It doesn't mark the partition(s) active.\n" 84224145Sdim"\n" 85224145Sdim"If a given <file> refers to a directory, the partition/device on which the\n" 86224145Sdim"directory resides will be made bootable. If it refers to a regular file,\n" 87224145Sdim"the file is considered a disk image and the boot code will be written to\n" 88224145Sdim"it.\n" 89224145Sdim"\n" 90224145Sdim"Options:\n" 91193323Sed" -h, --help - Print this help text and exit.\n" 92193323Sed" --dry-run - Do everything but actually writing the boot block to disk.\n" 93224145Sdim; 94210299Sed 95210299Sed 96224145Sdim// print_usage 97210299Sedstatic void 98210299Sedprint_usage(bool error) 99224145Sdim{ 100224145Sdim // get command name 101224145Sdim const char *commandName = NULL; 102210299Sed if (kArgc > 0) { 103210299Sed if (const char *lastSlash = strchr(kArgv[0], '/')) 104210299Sed commandName = lastSlash + 1; 105210299Sed else 106210299Sed commandName = kArgv[0]; 107210299Sed } 108210299Sed 109224145Sdim if (!commandName || strlen(commandName) == 0) 110224145Sdim commandName = kCommandName; 111210299Sed 112210299Sed // print usage 113212904Sdim fprintf((error ? stderr : stdout), kUsage, commandName, commandName, 114210299Sed commandName); 115210299Sed} 116210299Sed 117210299Sed 118210299Sed// print_usage_and_exit 119210299Sedstatic void 120210299Sedprint_usage_and_exit(bool error) 121210299Sed{ 122210299Sed print_usage(error); 123210299Sed exit(error ? 1 : 0); 124224145Sdim} 125210299Sed 126210299Sed 127210299Sed// read_boot_code_data 128210299Sedstatic uint8 * 129210299Sedread_boot_code_data(const char* programPath) 130210299Sed{ 131210299Sed // open our executable 132210299Sed BFile executableFile; 133210299Sed status_t error = executableFile.SetTo(programPath, B_READ_ONLY); 134210299Sed if (error != B_OK) { 135210299Sed fprintf(stderr, "Error: Failed to open my executable file (\"%s\": " 136210299Sed "%s\n", programPath, strerror(error)); 137210299Sed exit(1); 138210299Sed } 139210299Sed 140210299Sed uint8 *bootCodeData = new uint8[kBootCodeSize]; 141210299Sed 142210299Sed // open our resources 143210299Sed BResources resources; 144210299Sed error = resources.SetTo(&executableFile); 145210299Sed const void *resourceData = NULL; 146210299Sed if (error == B_OK) { 147210299Sed // read the boot block from the resources 148210299Sed size_t resourceSize; 149210299Sed resourceData = resources.LoadResource(B_RAW_TYPE, 666, &resourceSize); 150210299Sed 151210299Sed if (resourceData && resourceSize != (size_t)kBootCodeSize) { 152210299Sed resourceData = NULL; 153210299Sed printf("Warning: Something is fishy with my resources! The boot " 154210299Sed "code doesn't have the correct size. Trying the attribute " 155210299Sed "instead ...\n"); 156210299Sed } 157210299Sed } 158210299Sed 159210299Sed if (resourceData) { 160210299Sed // found boot data in the resources 161210299Sed memcpy(bootCodeData, resourceData, kBootCodeSize); 162210299Sed } else { 163210299Sed // no boot data in the resources; try the attribute 164210299Sed ssize_t bytesRead = executableFile.ReadAttr("BootCode", B_RAW_TYPE, 165210299Sed 0, bootCodeData, kBootCodeSize); 166210299Sed if (bytesRead < 0) { 167210299Sed fprintf(stderr, "Error: Failed to read boot code from resources " 168210299Sed "or attribute.\n"); 169210299Sed exit(1); 170210299Sed } 171210299Sed if (bytesRead != kBootCodeSize) { 172210299Sed fprintf(stderr, "Error: Failed to read boot code from resources, " 173210299Sed "and the boot code in the attribute has the wrong size!\n"); 174210299Sed exit(1); 175210299Sed } 176210299Sed } 177210299Sed 178210299Sed return bootCodeData; 179210299Sed} 180210299Sed 181210299Sed 182210299Sed// write_boot_code_part 183210299Sedstatic void 184210299Sedwrite_boot_code_part(const char *fileName, int fd, off_t imageOffset, 185210299Sed const uint8 *bootCodeData, int offset, int size, bool dryRun) 186210299Sed{ 187210299Sed if (!dryRun) { 188210299Sed ssize_t bytesWritten = write_pos(fd, imageOffset + offset, 189210299Sed bootCodeData + offset, size); 190210299Sed if (bytesWritten != size) { 191210299Sed fprintf(stderr, "Error: Failed to write to \"%s\": %s\n", fileName, 192210299Sed strerror(bytesWritten < 0 ? errno : B_ERROR)); 193210299Sed } 194210299Sed } 195210299Sed} 196210299Sed 197210299Sed 198210299Sed#ifdef HAIKU_TARGET_PLATFORM_HAIKU 199210299Sed 200210299Sedstatic status_t 201210299Sedfind_own_image(image_info *info) 202210299Sed{ 203210299Sed int32 cookie = 0; 204210299Sed while (get_next_image_info(B_CURRENT_TEAM, &cookie, info) == B_OK) { 205210299Sed if (((addr_t)info->text <= (addr_t)find_own_image 206210299Sed && (addr_t)info->text + info->text_size 207210299Sed > (addr_t)find_own_image)) { 208210299Sed return B_OK; 209210299Sed } 210210299Sed } 211210299Sed 212210299Sed return B_NAME_NOT_FOUND; 213210299Sed} 214224145Sdim 215210299Sed#endif 216210299Sed 217210299Sed 218210299Sed#if USE_PARTITION_MAP 219210299Sed 220210299Sedstatic void 221210299Seddump_partition_map(const PartitionMap& map) 222210299Sed{ 223210299Sed fprintf(stderr, "partitions:\n"); 224210299Sed int32 count = map.CountPartitions(); 225210299Sed for (int i = 0; i < count; i++) { 226210299Sed const Partition* partition = map.PartitionAt(i); 227210299Sed fprintf(stderr, "%2d: ", i); 228210299Sed if (partition == NULL) { 229210299Sed fprintf(stderr, "<null>\n"); 230210299Sed continue; 231210299Sed } 232210299Sed 233210299Sed if (partition->IsEmpty()) { 234210299Sed fprintf(stderr, "<empty>\n"); 235210299Sed continue; 236210299Sed } 237210299Sed 238210299Sed fprintf(stderr, "offset: %16" B_PRIdOFF ", size: %16" B_PRIdOFF 239210299Sed ", type: %x%s\n", partition->Offset(), partition->Size(), 240210299Sed partition->Type(), partition->IsExtended() ? " (extended)" : ""); 241210299Sed } 242210299Sed} 243224145Sdim 244210299Sed 245210299Sedstatic void 246210299Sedget_partition_offset(int deviceFD, off_t deviceStart, off_t deviceSize, 247224145Sdim int blockSize, int partitionIndex, char *deviceName, 248224145Sdim int64 &_partitionOffset) 249224145Sdim{ 250224145Sdim PartitionMapParser parser(deviceFD, deviceStart, deviceSize, blockSize); 251224145Sdim PartitionMap map; 252224145Sdim status_t error = parser.Parse(NULL, &map); 253224145Sdim if (error == B_OK) { 254224145Sdim Partition *partition = map.PartitionAt(partitionIndex - 1); 255224145Sdim if (!partition || partition->IsEmpty()) { 256224145Sdim fprintf(stderr, "Error: Invalid partition index %d.\n", 257224145Sdim partitionIndex); 258224145Sdim dump_partition_map(map); 259224145Sdim exit(1); 260224145Sdim } 261224145Sdim 262224145Sdim if (partition->IsExtended()) { 263224145Sdim fprintf(stderr, "Error: Partition %d is an extended " 264224145Sdim "partition.\n", partitionIndex); 265224145Sdim dump_partition_map(map); 266224145Sdim exit(1); 267224145Sdim } 268224145Sdim 269224145Sdim _partitionOffset = partition->Offset(); 270224145Sdim } else { 271224145Sdim // try again using GPT instead 272224145Sdim EFI::Header gptHeader(deviceFD, deviceSize, blockSize); 273224145Sdim error = gptHeader.InitCheck(); 274224145Sdim if (error == B_OK && partitionIndex < gptHeader.EntryCount()) { 275224145Sdim gpt_partition_entry partition = gptHeader.EntryAt(partitionIndex - 1); 276224145Sdim 277224145Sdim static_guid bfs_uuid = {0x42465331, 0x3BA3, 0x10F1, 278224145Sdim 0x802A4861696B7521LL}; 279224145Sdim 280224145Sdim if (!(bfs_uuid == partition.partition_type)) { 281224145Sdim fprintf(stderr, "Error: Partition %d does not have the " 282224145Sdim "BFS UUID.\n", partitionIndex); 283224145Sdim exit(1); 284224145Sdim } 285224145Sdim 286224145Sdim _partitionOffset = partition.StartBlock() * blockSize; 287224145Sdim } else { 288224145Sdim fprintf(stderr, "Error: Parsing partition table on device " 289224145Sdim "\"%s\" failed: %s\n", deviceName, strerror(error)); 290224145Sdim exit(1); 291224145Sdim } 292224145Sdim } 293224145Sdim 294224145Sdim close(deviceFD); 295224145Sdim} 296224145Sdim 297224145Sdim#endif 298224145Sdim 299224145Sdim 300224145Sdim// main 301224145Sdimint 302224145Sdimmain(int argc, const char *const *argv) 303224145Sdim{ 304224145Sdim kArgc = argc; 305224145Sdim kArgv = argv; 306224145Sdim 307224145Sdim if (argc < 2) 308224145Sdim print_usage_and_exit(true); 309224145Sdim 310224145Sdim // parameters 311224145Sdim const char **files = new const char*[argc]; 312224145Sdim int fileCount = 0; 313224145Sdim bool dryRun = false; 314224145Sdim off_t startOffset = 0; 315224145Sdim 316224145Sdim // parse arguments 317224145Sdim for (int argi = 1; argi < argc;) { 318224145Sdim const char *arg = argv[argi++]; 319224145Sdim 320224145Sdim if (arg[0] == '-') { 321224145Sdim if (strcmp(arg, "-h") == 0 || strcmp(arg, "--help") == 0) { 322224145Sdim print_usage_and_exit(false); 323224145Sdim } else if (strcmp(arg, "--dry-run") == 0) { 324224145Sdim dryRun = true; 325224145Sdim } else if (strcmp(arg, "--start-offset") == 0) { 326224145Sdim if (argi >= argc) 327224145Sdim print_usage_and_exit(true); 328224145Sdim startOffset = strtoll(argv[argi++], NULL, 0); 329224145Sdim } else { 330224145Sdim print_usage_and_exit(true); 331224145Sdim } 332224145Sdim 333224145Sdim } else { 334224145Sdim files[fileCount++] = arg; 335224145Sdim } 336224145Sdim } 337224145Sdim 338224145Sdim // we need at least one file 339224145Sdim if (fileCount == 0) 340224145Sdim print_usage_and_exit(true); 341224145Sdim 342224145Sdim // read the boot code 343224145Sdim uint8 *bootCodeData = NULL; 344224145Sdim#ifndef HAIKU_TARGET_PLATFORM_HAIKU 345224145Sdim bootCodeData = read_boot_code_data(argv[0]); 346224145Sdim#else 347224145Sdim image_info info; 348224145Sdim if (find_own_image(&info) == B_OK) 349224145Sdim bootCodeData = read_boot_code_data(info.name); 350224145Sdim#endif 351224145Sdim if (!bootCodeData) { 352224145Sdim fprintf(stderr, "Error: Failed to read \n"); 353224145Sdim exit(1); 354224145Sdim } 355224145Sdim 356224145Sdim // iterate through the files and make them bootable 357224145Sdim status_t error; 358224145Sdim for (int i = 0; i < fileCount; i++) { 359224145Sdim const char *fileName = files[i]; 360224145Sdim BEntry entry; 361224145Sdim error = entry.SetTo(fileName, true); 362224145Sdim if (error != B_OK) { 363224145Sdim fprintf(stderr, "Error: Failed to open \"%s\": %s\n", 364224145Sdim fileName, strerror(error)); 365224145Sdim exit(1); 366224145Sdim } 367224145Sdim 368224145Sdim // get stat to check the type of the file 369224145Sdim struct stat st; 370224145Sdim error = entry.GetStat(&st); 371224145Sdim if (error != B_OK) { 372224145Sdim fprintf(stderr, "Error: Failed to stat \"%s\": %s\n", 373224145Sdim fileName, strerror(error)); 374224145Sdim exit(1); 375224145Sdim } 376224145Sdim 377224145Sdim bool noPartition = false; 378224145Sdim int64 partitionOffset = 0; 379224145Sdim fs_info info; // needs to be here (we use the device name later) 380224145Sdim if (S_ISDIR(st.st_mode)) { 381224145Sdim #ifdef HAIKU_TARGET_PLATFORM_HAIKU 382224145Sdim 383224145Sdim // a directory: get the device 384224145Sdim error = fs_stat_dev(st.st_dev, &info); 385224145Sdim if (error != B_OK) { 386224145Sdim fprintf(stderr, "Error: Failed to determine device for " 387224145Sdim "\"%s\": %s\n", fileName, strerror(error)); 388224145Sdim exit(1); 389224145Sdim } 390224145Sdim 391224145Sdim fileName = info.device_name; 392224145Sdim 393224145Sdim #else 394224145Sdim 395224145Sdim (void)info; 396224145Sdim fprintf(stderr, "Error: Specifying directories not supported " 397224145Sdim "on this platform!\n"); 398224145Sdim exit(1); 399224145Sdim 400224145Sdim #endif 401224145Sdim 402224145Sdim } else if (S_ISREG(st.st_mode)) { 403224145Sdim // a regular file: fine 404224145Sdim noPartition = true; 405224145Sdim } else if (S_ISCHR(st.st_mode)) { 406224145Sdim // character special: a device or partition under BeOS 407224145Sdim // or under FreeBSD 408224145Sdim #if !defined(HAIKU_TARGET_PLATFORM_HAIKU) \ 409224145Sdim && !defined(HAIKU_HOST_PLATFORM_FREEBSD) 410224145Sdim 411224145Sdim fprintf(stderr, "Error: Character special devices not " 412224145Sdim "supported on this platform.\n"); 413224145Sdim exit(1); 414224145Sdim 415224145Sdim #endif 416224145Sdim 417224145Sdim #ifdef HAIKU_HOST_PLATFORM_FREEBSD 418224145Sdim 419224145Sdim // chop off the trailing number 420224145Sdim int fileNameLen = strlen(fileName); 421224145Sdim int baseNameLen = -1; 422224145Sdim for (int k = fileNameLen - 1; k >= 0; k--) { 423224145Sdim if (!isdigit(fileName[k])) { 424224145Sdim baseNameLen = k + 1; 425224145Sdim break; 426224145Sdim } 427224145Sdim } 428224145Sdim 429224145Sdim // Remove de 's' from 'ad2s2' slice device (partition for DOS 430224145Sdim // users) to get 'ad2' base device 431224145Sdim baseNameLen--; 432224145Sdim 433224145Sdim if (baseNameLen < 0) { 434224145Sdim // only digits? 435224145Sdim fprintf(stderr, "Error: Failed to get base device name.\n"); 436224145Sdim exit(1); 437224145Sdim } 438224145Sdim 439224145Sdim if (baseNameLen < fileNameLen) { 440224145Sdim // get base device name and partition index 441224145Sdim char baseDeviceName[B_PATH_NAME_LENGTH]; 442224145Sdim int partitionIndex = atoi(fileName + baseNameLen + 1); 443224145Sdim // Don't forget the 's' of slice :) 444224145Sdim memcpy(baseDeviceName, fileName, baseNameLen); 445224145Sdim baseDeviceName[baseNameLen] = '\0'; 446224145Sdim 447224145Sdim // open base device 448224145Sdim int baseFD = open(baseDeviceName, O_RDONLY); 449224145Sdim if (baseFD < 0) { 450224145Sdim fprintf(stderr, "Error: Failed to open \"%s\": %s\n", 451224145Sdim baseDeviceName, strerror(errno)); 452224145Sdim exit(1); 453224145Sdim } 454224145Sdim 455224145Sdim // get device size 456224145Sdim int64 deviceSize; 457224145Sdim if (ioctl(baseFD, DIOCGMEDIASIZE, &deviceSize) == -1) { 458224145Sdim fprintf(stderr, "Error: Failed to get device geometry " 459224145Sdim "for \"%s\": %s\n", baseDeviceName, 460224145Sdim strerror(errno)); 461224145Sdim exit(1); 462224145Sdim } 463224145Sdim 464224145Sdim // parse the partition map 465224145Sdim // TODO: block size! 466224145Sdim get_partition_offset(baseFD, 0, deviceSize, 512, 467224145Sdim partitionIndex, baseDeviceName, partitionOffset); 468224145Sdim } else { 469224145Sdim // The given device is the base device. We'll write at 470224145Sdim // offset 0. 471224145Sdim } 472224145Sdim 473224145Sdim #endif // HAIKU_HOST_PLATFORM_FREEBSD 474224145Sdim 475224145Sdim } else if (S_ISBLK(st.st_mode)) { 476224145Sdim // block device: a device or partition under Linux or Darwin 477224145Sdim #ifdef HAIKU_HOST_PLATFORM_LINUX 478224145Sdim 479224145Sdim // chop off the trailing number 480224145Sdim int fileNameLen = strlen(fileName); 481224145Sdim int baseNameLen = -1; 482224145Sdim for (int k = fileNameLen - 1; k >= 0; k--) { 483224145Sdim if (!isdigit(fileName[k])) { 484224145Sdim baseNameLen = k + 1; 485224145Sdim break; 486224145Sdim } 487224145Sdim } 488224145Sdim 489224145Sdim if (baseNameLen < 0) { 490224145Sdim // only digits? 491224145Sdim fprintf(stderr, "Error: Failed to get base device name.\n"); 492224145Sdim exit(1); 493224145Sdim } 494224145Sdim 495224145Sdim if (baseNameLen < fileNameLen) { 496224145Sdim // get base device name and partition index 497224145Sdim char baseDeviceName[B_PATH_NAME_LENGTH]; 498224145Sdim int partitionIndex = atoi(fileName + baseNameLen); 499224145Sdim memcpy(baseDeviceName, fileName, baseNameLen); 500224145Sdim baseDeviceName[baseNameLen] = '\0'; 501224145Sdim 502224145Sdim // open base device 503224145Sdim int baseFD = open(baseDeviceName, O_RDONLY); 504224145Sdim if (baseFD < 0) { 505224145Sdim fprintf(stderr, "Error: Failed to open \"%s\": %s\n", 506224145Sdim baseDeviceName, strerror(errno)); 507224145Sdim exit(1); 508224145Sdim } 509224145Sdim 510224145Sdim // get device size -- try BLKGETSIZE64, but, if it doesn't 511224145Sdim // work, fall back to the obsolete HDIO_GETGEO 512224145Sdim int64 deviceSize; 513224145Sdim hd_geometry geometry; 514224145Sdim if (ioctl(baseFD, BLKGETSIZE64, &deviceSize) == 0 515224145Sdim && deviceSize > 0) { 516224145Sdim // looks good 517224145Sdim } else if (ioctl(baseFD, HDIO_GETGEO, &geometry) == 0) { 518224145Sdim deviceSize = (int64)geometry.heads * geometry.sectors 519224145Sdim * geometry.cylinders * 512; 520224145Sdim } else { 521224145Sdim fprintf(stderr, "Error: Failed to get device geometry " 522224145Sdim "for \"%s\": %s\n", baseDeviceName, 523224145Sdim strerror(errno)); 524224145Sdim exit(1); 525224145Sdim } 526224145Sdim 527224145Sdim // parse the partition map 528224145Sdim // TODO: block size! 529224145Sdim get_partition_offset(baseFD, 0, deviceSize, 512, 530224145Sdim partitionIndex, baseDeviceName, partitionOffset); 531224145Sdim } else { 532224145Sdim // The given device is the base device. We'll write at 533224145Sdim // offset 0. 534224145Sdim } 535224145Sdim 536224145Sdim #elif defined(HAIKU_HOST_PLATFORM_DARWIN) 537224145Sdim // chop off the trailing number 538224145Sdim int fileNameLen = strlen(fileName); 539224145Sdim int baseNameLen = fileNameLen - 2; 540224145Sdim 541224145Sdim // get base device name and partition index 542224145Sdim char baseDeviceName[B_PATH_NAME_LENGTH]; 543224145Sdim int partitionIndex = atoi(fileName + baseNameLen + 1); 544224145Sdim memcpy(baseDeviceName, fileName, baseNameLen); 545224145Sdim baseDeviceName[baseNameLen] = '\0'; 546224145Sdim 547224145Sdim // open base device 548224145Sdim int baseFD = open(baseDeviceName, O_RDONLY); 549224145Sdim if (baseFD < 0) { 550224145Sdim fprintf(stderr, "Error: Failed to open \"%s\": %s\n", 551224145Sdim baseDeviceName, strerror(errno)); 552224145Sdim exit(1); 553224145Sdim } 554224145Sdim 555224145Sdim // get device size 556224145Sdim int64 blockSize; 557224145Sdim int64 blockCount; 558224145Sdim int64 deviceSize; 559224145Sdim if (ioctl(baseFD, DKIOCGETBLOCKSIZE, &blockSize) == -1) { 560224145Sdim fprintf(stderr, "Error: Failed to get block size " 561224145Sdim "for \"%s\": %s\n", baseDeviceName, 562224145Sdim strerror(errno)); 563224145Sdim exit(1); 564224145Sdim } 565224145Sdim if (ioctl(baseFD, DKIOCGETBLOCKCOUNT, &blockCount) == -1) { 566224145Sdim fprintf(stderr, "Error: Failed to get block count " 567224145Sdim "for \"%s\": %s\n", baseDeviceName, 568224145Sdim strerror(errno)); 569224145Sdim exit(1); 570224145Sdim } 571224145Sdim 572224145Sdim deviceSize = blockSize * blockCount; 573224145Sdim 574224145Sdim // parse the partition map 575224145Sdim get_partition_offset(baseFD, 0, deviceSize, 512, 576224145Sdim partitionIndex, baseDeviceName, partitionOffset); 577224145Sdim #else 578224145Sdim // partitions are block devices under Haiku, but not under BeOS 579224145Sdim #ifdef HAIKU_TARGET_PLATFORM_HAIKU 580224145Sdim fprintf(stderr, "Error: Block devices not supported on this " 581224145Sdim "platform!\n"); 582224145Sdim exit(1); 583224145Sdim #endif // HAIKU_TARGET_PLATFORM_HAIKU 584224145Sdim 585224145Sdim #endif 586224145Sdim } else { 587224145Sdim fprintf(stderr, "Error: File type of \"%s\" is not supported.\n", 588224145Sdim fileName); 589224145Sdim exit(1); 590224145Sdim } 591224145Sdim 592224145Sdim // open the file 593224145Sdim int fd = open(fileName, O_RDWR); 594224145Sdim if (fd < 0) { 595224145Sdim fprintf(stderr, "Error: Failed to open \"%s\": %s\n", fileName, 596224145Sdim strerror(errno)); 597224145Sdim exit(1); 598224145Sdim } 599224145Sdim 600224145Sdim #ifdef HAIKU_TARGET_PLATFORM_HAIKU 601224145Sdim 602224145Sdim // get a partition info 603224145Sdim if (!noPartition 604224145Sdim && strlen(fileName) >= 3 605224145Sdim && strncmp("raw", fileName + strlen(fileName) - 3, 3)) { 606224145Sdim partition_info partitionInfo; 607224145Sdim if (ioctl(fd, B_GET_PARTITION_INFO, &partitionInfo, 608224145Sdim sizeof(partitionInfo)) == 0) { 609224145Sdim partitionOffset = partitionInfo.offset; 610224145Sdim } else { 611224145Sdim fprintf(stderr, "Error: Failed to get partition info: %s\n", 612224145Sdim strerror(errno)); 613224145Sdim exit(1); 614224145Sdim } 615224145Sdim } 616224145Sdim 617224145Sdim #endif // HAIKU_TARGET_PLATFORM_HAIKU 618224145Sdim 619224145Sdim // adjust the partition offset in the boot code data 620224145Sdim // hard coded sector size: 512 bytes 621224145Sdim *(uint32*)(bootCodeData + kPartitionOffsetOffset) 622224145Sdim = B_HOST_TO_LENDIAN_INT32((uint32)(partitionOffset / 512)); 623224145Sdim 624224145Sdim // write the boot code 625224145Sdim printf("Writing boot code to \"%s\" (partition offset: %" B_PRId64 626224145Sdim " bytes, start offset = %" B_PRIdOFF ") " 627224145Sdim "...\n", fileName, partitionOffset, startOffset); 628224145Sdim 629224145Sdim write_boot_code_part(fileName, fd, startOffset, bootCodeData, 0, 630224145Sdim kFirstBootCodePartSize, dryRun); 631224145Sdim write_boot_code_part(fileName, fd, startOffset, bootCodeData, 632224145Sdim kSecondBootCodePartOffset, kSecondBootCodePartSize, 633224145Sdim dryRun); 634224145Sdim 635224145Sdim#ifdef HAIKU_TARGET_PLATFORM_HAIKU 636224145Sdim // check if this partition is mounted 637224145Sdim BDiskDeviceRoster roster; 638224145Sdim BPartition* partition; 639224145Sdim BDiskDevice device; 640224145Sdim status_t status = roster.GetPartitionForPath(fileName, &device, 641224145Sdim &partition); 642224145Sdim if (status != B_OK) { 643224145Sdim status = roster.GetFileDeviceForPath(fileName, &device); 644224145Sdim if (status == B_OK) 645224145Sdim partition = &device; 646224145Sdim } 647224145Sdim if (status == B_OK && partition->IsMounted() && !dryRun) { 648224145Sdim // This partition is mounted, we need to tell BFS to update its 649224145Sdim // boot block (we are using part of the same logical block). 650224145Sdim BPath path; 651224145Sdim status = partition->GetMountPoint(&path); 652224145Sdim if (status == B_OK) { 653224145Sdim update_boot_block update; 654224145Sdim update.offset = kSecondBootCodePartOffset - 512; 655224145Sdim update.data = bootCodeData + kSecondBootCodePartOffset; 656224145Sdim update.length = kSecondBootCodePartSize; 657224145Sdim 658224145Sdim int mountFD = open(path.Path(), O_RDONLY); 659224145Sdim if (ioctl(mountFD, BFS_IOCTL_UPDATE_BOOT_BLOCK, &update, 660224145Sdim sizeof(update_boot_block)) != 0) { 661224145Sdim fprintf(stderr, "Could not update BFS boot block: %s\n", 662224145Sdim strerror(errno)); 663224145Sdim } 664224145Sdim close(mountFD); 665224145Sdim } else { 666224145Sdim fprintf(stderr, "Could not update BFS boot code while the " 667224145Sdim "partition is mounted!\n"); 668224145Sdim } 669224145Sdim } 670224145Sdim#endif // HAIKU_TARGET_PLATFORM_HAIKU 671224145Sdim 672224145Sdim close(fd); 673224145Sdim } 674224145Sdim 675224145Sdim delete[] files; 676224145Sdim 677224145Sdim return 0; 678224145Sdim} 679224145Sdim