void AutoMounter::_UnmountAndEjectVolume(BMessage* message) { int32 id; if (message->FindInt32("id", &id) == B_OK) { BDiskDeviceRoster roster; BPartition *partition; BDiskDevice device; if (roster.GetPartitionWithID(id, &device, &partition) != B_OK) return; BPath path; if (partition->GetMountPoint(&path) == B_OK) _UnmountAndEjectVolume(partition, path, partition->ContentName()); } else { // see if we got a dev_t dev_t device; if (message->FindInt32("device_id", &device) != B_OK) return; BVolume volume(device); status_t status = volume.InitCheck(); char name[B_FILE_NAME_LENGTH]; if (status == B_OK) status = volume.GetName(name); if (status < B_OK) snprintf(name, sizeof(name), "device:%" B_PRIdDEV, device); BPath path; if (status == B_OK) { BDirectory mountPoint; status = volume.GetRootDirectory(&mountPoint); if (status == B_OK) status = path.SetTo(&mountPoint, "."); } if (status == B_OK) _UnmountAndEjectVolume(NULL, path, name); } }
void InstallerWindow::_PublishPackages() { fPackagesView->Clean(); PartitionMenuItem *item = (PartitionMenuItem *)fSrcMenu->FindMarked(); if (!item) return; BPath directory; BDiskDeviceRoster roster; BDiskDevice device; BPartition *partition; if (roster.GetPartitionWithID(item->ID(), &device, &partition) == B_OK) { if (partition->GetMountPoint(&directory) != B_OK) return; } else if (roster.GetDeviceWithID(item->ID(), &device) == B_OK) { if (device.GetMountPoint(&directory) != B_OK) return; } else return; // shouldn't happen directory.Append(PACKAGES_DIRECTORY); BDirectory dir(directory.Path()); if (dir.InitCheck() != B_OK) return; BEntry packageEntry; BList packages; while (dir.GetNextEntry(&packageEntry) == B_OK) { Package* package = Package::PackageFromEntry(packageEntry); if (package != NULL) packages.AddItem(package); } packages.SortItems(_ComparePackages); fPackagesView->AddPackages(packages, new BMessage(PACKAGE_CHECKBOX)); PostMessage(PACKAGE_CHECKBOX); }
void MainWindow::_Unmount(BDiskDevice* disk, partition_id selectedPartition) { if (!disk || selectedPartition < 0) { _DisplayPartitionError(B_TRANSLATE("You need to select a partition " "entry from the list.")); return; } BPartition* partition = disk->FindDescendant(selectedPartition); if (!partition) { _DisplayPartitionError(B_TRANSLATE("Unable to find the selected " "partition by ID.")); return; } if (partition->IsMounted()) { BPath path; partition->GetMountPoint(&path); status_t ret = partition->Unmount(); if (ret < B_OK) { _DisplayPartitionError( B_TRANSLATE("Could not unmount partition %s."), partition, ret); } else { if (dev_for_path(path.Path()) == dev_for_path("/")) rmdir(path.Path()); // successful unmount, adapt to the changes _ScanDrives(); } } else { _DisplayPartitionError( B_TRANSLATE("The partition %s is already unmounted."), partition); } }
void WorkerThread::MessageReceived(BMessage* message) { CALLED(); switch (message->what) { case MSG_START_INSTALLING: _PerformInstall(fWindow->GetSourceMenu(), fWindow->GetTargetMenu()); break; case MSG_WRITE_BOOT_SECTOR: { int32 id; if (message->FindInt32("id", &id) != B_OK) { _SetStatusMessage(B_TRANSLATE("Boot sector not written " "because of an internal error.")); break; } // TODO: Refactor with _PerformInstall() BPath targetDirectory; BDiskDevice device; BPartition* partition; if (fDDRoster.GetPartitionWithID(id, &device, &partition) == B_OK) { if (!partition->IsMounted()) { if (partition->Mount() < B_OK) { _SetStatusMessage(B_TRANSLATE("The partition can't be " "mounted. Please choose a different partition.")); break; } } if (partition->GetMountPoint(&targetDirectory) != B_OK) { _SetStatusMessage(B_TRANSLATE("The mount point could not " "be retrieved.")); break; } } else if (fDDRoster.GetDeviceWithID(id, &device) == B_OK) { if (!device.IsMounted()) { if (device.Mount() < B_OK) { _SetStatusMessage(B_TRANSLATE("The disk can't be " "mounted. Please choose a different disk.")); break; } } if (device.GetMountPoint(&targetDirectory) != B_OK) { _SetStatusMessage(B_TRANSLATE("The mount point could not " "be retrieved.")); break; } } _LaunchFinishScript(targetDirectory); // TODO: Get error from executing script! _SetStatusMessage( B_TRANSLATE("Boot sector successfully written.")); } default: BLooper::MessageReceived(message); } }
void WorkerThread::_PerformInstall(BMenu* srcMenu, BMenu* targetMenu) { CALLED(); BPath targetDirectory; BPath srcDirectory; BPath trashPath; BPath testPath; BDirectory targetDir; BDiskDevice device; BPartition* partition; BVolume targetVolume; status_t err = B_OK; int32 entries = 0; entry_ref testRef; const char* mountError = B_TRANSLATE("The disk can't be mounted. Please " "choose a different disk."); BMessenger messenger(fWindow); ProgressReporter reporter(messenger, new BMessage(MSG_STATUS_MESSAGE)); CopyEngine engine(&reporter); BList unzipEngines; PartitionMenuItem* targetItem = (PartitionMenuItem*)targetMenu->FindMarked(); PartitionMenuItem* srcItem = (PartitionMenuItem*)srcMenu->FindMarked(); if (!srcItem || !targetItem) { ERR("bad menu items\n"); goto error; } // check if target is initialized // ask if init or mount as is if (fDDRoster.GetPartitionWithID(targetItem->ID(), &device, &partition) == B_OK) { if (!partition->IsMounted()) { if ((err = partition->Mount()) < B_OK) { _SetStatusMessage(mountError); ERR("BPartition::Mount"); goto error; } } if ((err = partition->GetVolume(&targetVolume)) != B_OK) { ERR("BPartition::GetVolume"); goto error; } if ((err = partition->GetMountPoint(&targetDirectory)) != B_OK) { ERR("BPartition::GetMountPoint"); goto error; } } else if (fDDRoster.GetDeviceWithID(targetItem->ID(), &device) == B_OK) { if (!device.IsMounted()) { if ((err = device.Mount()) < B_OK) { _SetStatusMessage(mountError); ERR("BDiskDevice::Mount"); goto error; } } if ((err = device.GetVolume(&targetVolume)) != B_OK) { ERR("BDiskDevice::GetVolume"); goto error; } if ((err = device.GetMountPoint(&targetDirectory)) != B_OK) { ERR("BDiskDevice::GetMountPoint"); goto error; } } else goto error; // shouldn't happen // check if target has enough space if ((fSpaceRequired > 0 && targetVolume.FreeBytes() < fSpaceRequired) && ((new BAlert("", B_TRANSLATE("The destination disk may not have " "enough space. Try choosing a different disk or choose to not " "install optional items."), B_TRANSLATE("Try installing anyway"), B_TRANSLATE("Cancel"), 0, B_WIDTH_AS_USUAL, B_STOP_ALERT))->Go() != 0)) { goto error; } if (fDDRoster.GetPartitionWithID(srcItem->ID(), &device, &partition) == B_OK) { if ((err = partition->GetMountPoint(&srcDirectory)) != B_OK) { ERR("BPartition::GetMountPoint"); goto error; } } else if (fDDRoster.GetDeviceWithID(srcItem->ID(), &device) == B_OK) { if ((err = device.GetMountPoint(&srcDirectory)) != B_OK) { ERR("BDiskDevice::GetMountPoint"); goto error; } } else goto error; // shouldn't happen // check not installing on itself if (strcmp(srcDirectory.Path(), targetDirectory.Path()) == 0) { _SetStatusMessage(B_TRANSLATE("You can't install the contents of a " "disk onto itself. Please choose a different disk.")); goto error; } // check not installing on boot volume if ((strncmp(BOOT_PATH, targetDirectory.Path(), strlen(BOOT_PATH)) == 0) && ((new BAlert("", B_TRANSLATE("Are you sure you want to install " "onto the current boot disk? The Installer will have to reboot " "your machine if you proceed."), B_TRANSLATE("OK"), B_TRANSLATE("Cancel"), 0, B_WIDTH_AS_USUAL, B_STOP_ALERT))->Go() != 0)) { _SetStatusMessage("Installation stopped."); goto error; } // check if target volume's trash dir has anything in it // (target volume w/ only an empty trash dir is considered // an empty volume) if (find_directory(B_TRASH_DIRECTORY, &trashPath, false, &targetVolume) == B_OK && targetDir.SetTo(trashPath.Path()) == B_OK) { while (targetDir.GetNextRef(&testRef) == B_OK) { // Something in the Trash entries++; break; } } targetDir.SetTo(targetDirectory.Path()); // check if target volume otherwise has any entries while (entries == 0 && targetDir.GetNextRef(&testRef) == B_OK) { if (testPath.SetTo(&testRef) == B_OK && testPath != trashPath) entries++; } if (entries != 0 && ((new BAlert("", B_TRANSLATE("The target volume is not empty. Are " "you sure you want to install anyway?\n\nNote: The 'system' folder " "will be a clean copy from the source volume, all other folders " "will be merged, whereas files and links that exist on both the " "source and target volume will be overwritten with the source " "volume version."), B_TRANSLATE("Install anyway"), B_TRANSLATE("Cancel"), 0, B_WIDTH_AS_USUAL, B_STOP_ALERT))->Go() != 0)) { // TODO: Would be cool to offer the option here to clean additional // folders at the user's choice (like /boot/common and /boot/develop). err = B_CANCELED; goto error; } // Begin actual installation _LaunchInitScript(targetDirectory); // Create the default indices which should always be present on a proper // boot volume. We don't care if the source volume does not have them. // After all, the user might be re-installing to another drive and may // want problems fixed along the way... err = _CreateDefaultIndices(targetDirectory); if (err != B_OK) goto error; // Mirror all the indices which are present on the source volume onto // the target volume. err = _MirrorIndices(srcDirectory, targetDirectory); if (err != B_OK) goto error; // Let the engine collect information for the progress bar later on engine.ResetTargets(srcDirectory.Path()); err = engine.CollectTargets(srcDirectory.Path(), fCancelSemaphore); if (err != B_OK) goto error; // Collect selected packages also if (fPackages) { BPath pkgRootDir(srcDirectory.Path(), PACKAGES_DIRECTORY); int32 count = fPackages->CountItems(); for (int32 i = 0; i < count; i++) { Package *p = static_cast<Package*>(fPackages->ItemAt(i)); BPath packageDir(pkgRootDir.Path(), p->Folder()); err = engine.CollectTargets(packageDir.Path(), fCancelSemaphore); if (err != B_OK) goto error; } } // collect information about all zip packages err = _ProcessZipPackages(srcDirectory.Path(), targetDirectory.Path(), &reporter, unzipEngines); if (err != B_OK) goto error; reporter.StartTimer(); // copy source volume err = engine.CopyFolder(srcDirectory.Path(), targetDirectory.Path(), fCancelSemaphore); if (err != B_OK) goto error; // copy selected packages if (fPackages) { BPath pkgRootDir(srcDirectory.Path(), PACKAGES_DIRECTORY); int32 count = fPackages->CountItems(); for (int32 i = 0; i < count; i++) { Package *p = static_cast<Package*>(fPackages->ItemAt(i)); BPath packageDir(pkgRootDir.Path(), p->Folder()); err = engine.CopyFolder(packageDir.Path(), targetDirectory.Path(), fCancelSemaphore); if (err != B_OK) goto error; } } // Extract all zip packages. If an error occured, delete the rest of // the engines, but stop extracting. for (int32 i = 0; i < unzipEngines.CountItems(); i++) { UnzipEngine* engine = reinterpret_cast<UnzipEngine*>( unzipEngines.ItemAtFast(i)); if (err == B_OK) err = engine->UnzipPackage(); delete engine; } if (err != B_OK) goto error; _LaunchFinishScript(targetDirectory); BMessenger(fWindow).SendMessage(MSG_INSTALL_FINISHED); return; error: BMessage statusMessage(MSG_RESET); if (err == B_CANCELED) _SetStatusMessage(B_TRANSLATE("Installation canceled.")); else statusMessage.AddInt32("error", err); ERR("_PerformInstall failed"); BMessenger(fWindow).SendMessage(&statusMessage); }
void MountVolume::ArgvReceived(int32 argc, char** argv) { MountVisitor mountVisitor; PrintPartitionsVisitor printPartitionsVisitor; bool listAllDevices = false; if (argc < 2) printPartitionsVisitor.listMountablePartitions = true; // parse arguments for (int argi = 1; argi < argc; argi++) { const char* arg = argv[argi]; if (arg[0] != '\0' && arg[0] != '-') { mountVisitor.toMount.insert(arg); } else if (strcmp(arg, "-s") == 0) { mountVisitor.silent = true; } else if (strcmp(arg, "-h") == 0 || strcmp(arg, "--help") == 0) { print_usage_and_exit(false); } else if (strcmp(arg, "-all") == 0) { mountVisitor.mountAll = true; } else if (strcmp(arg, "-allbfs") == 0) { mountVisitor.mountBFS = true; } else if (strcmp(arg, "-allhfs") == 0) { mountVisitor.mountHFS = true; } else if (strcmp(arg, "-alldos") == 0) { mountVisitor.mountDOS = true; } else if (strcmp(arg, "-ro") == 0 || strcmp(arg, "-readonly") == 0) { mountVisitor.readOnly = true; } else if (strcmp(arg, "-u") == 0 || strcmp(arg, "-unmount") == 0) { argi++; if (argi >= argc) print_usage_and_exit(true); mountVisitor.toUnmount.insert(argv[argi]); } else if (strcmp(arg, "-p") == 0 || strcmp(arg, "-l") == 0) { printPartitionsVisitor.listMountablePartitions = true; } else if (strcmp(arg, "-lh") == 0) { printPartitionsVisitor.listAllPartitions = true; } else if (strcmp(arg, "-dd") == 0) { listAllDevices = true; } else if (strcmp(arg, "-r") == 0 || strcmp(arg, "-publishall") == 0 || strcmp(arg, "-publishbfs") == 0 || strcmp(arg, "-publishhfs") == 0 || strcmp(arg, "-publishdos") == 0) { // obsolete: ignore } else print_usage_and_exit(true); } // get a disk device list BDiskDeviceList deviceList; status_t error = deviceList.Fetch(); if (error != B_OK) { fprintf(stderr, "Failed to get the list of disk devices: %s", strerror(error)); exit(1); } // mount/unmount volumes deviceList.VisitEachMountablePartition(&mountVisitor); BDiskDeviceRoster roster; // try mount file images for (StringSet::iterator iterator = mountVisitor.toMount.begin(); iterator != mountVisitor.toMount.end();) { const char* name = (*iterator).c_str(); iterator++; BEntry entry(name, true); if (!entry.Exists()) continue; // TODO: improve error messages BPath path; if (entry.GetPath(&path) != B_OK) continue; partition_id id = -1; BDiskDevice device; BPartition* partition; if (!strncmp(path.Path(), "/dev/", 5)) { // seems to be a device path if (roster.GetPartitionForPath(path.Path(), &device, &partition) != B_OK) continue; } else { // a file with this name exists, so try to mount it id = roster.RegisterFileDevice(path.Path()); if (id < 0) continue; if (roster.GetPartitionWithID(id, &device, &partition) != B_OK) { roster.UnregisterFileDevice(id); continue; } } status_t status = partition->Mount(NULL, mountVisitor.readOnly ? B_MOUNT_READ_ONLY : 0); if (!mountVisitor.silent) { if (status >= B_OK) { BPath mountPoint; partition->GetMountPoint(&mountPoint); printf("%s \"%s\" mounted successfully at \"%s\".\n", id < 0 ? "Device" : "Image", name, mountPoint.Path()); } } if (status >= B_OK) { // remove from list mountVisitor.toMount.erase(name); } else if (id >= 0) roster.UnregisterFileDevice(id); } // TODO: support unmounting images by path! // print errors for the volumes to mount/unmount, that weren't found if (!mountVisitor.silent) { for (StringSet::iterator it = mountVisitor.toMount.begin(); it != mountVisitor.toMount.end(); it++) { fprintf(stderr, "Failed to mount volume `%s': Volume not found.\n", (*it).c_str()); } for (StringSet::iterator it = mountVisitor.toUnmount.begin(); it != mountVisitor.toUnmount.end(); it++) { fprintf(stderr, "Failed to unmount volume `%s': Volume not " "found.\n", (*it).c_str()); } } // update the disk device list error = deviceList.Fetch(); if (error != B_OK) { fprintf(stderr, "Failed to update the list of disk devices: %s", strerror(error)); exit(1); } // print information if (listAllDevices) { // TODO } // determine width of the terminal in order to shrink the columns if needed if (isatty(STDOUT_FILENO)) { winsize size; if (ioctl(STDOUT_FILENO, TIOCGWINSZ, &size, sizeof(winsize)) == 0) { if (size.ws_col < 95) { sVolumeNameWidth -= (95 - size.ws_col) / 2; sFSNameWidth -= (95 - size.ws_col) / 2; } } } if (printPartitionsVisitor.IsUsed()) { printf("%-*s %-*s Size Mounted At (Device)\n", sVolumeNameWidth, "Volume", sFSNameWidth, "File System"); BString separator; separator.SetTo('-', sVolumeNameWidth + sFSNameWidth + 35); puts(separator.String()); if (printPartitionsVisitor.listAllPartitions) deviceList.VisitEachPartition(&printPartitionsVisitor); else deviceList.VisitEachMountablePartition(&printPartitionsVisitor); } exit(0); }
// main int main(int argc, const char *const *argv) { kArgc = argc; kArgv = argv; if (argc < 2) print_usage_and_exit(true); // parameters const char **files = new const char*[argc]; int fileCount = 0; bool dryRun = false; off_t startOffset = 0; // parse arguments for (int argi = 1; argi < argc;) { const char *arg = argv[argi++]; 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, "--start-offset") == 0) { if (argi >= argc) print_usage_and_exit(true); startOffset = strtoll(argv[argi++], NULL, 0); } else if (strcmp(arg, "-safe") == 0) { fprintf(stderr, "Error: Sorry, BeOS R3 isn't supported!\n"); exit(1); } else { print_usage_and_exit(true); } } else { files[fileCount++] = arg; } } // we need at least one file if (fileCount == 0) print_usage_and_exit(true); // read the boot code uint8 *bootCodeData = NULL; #ifndef __ANTARES__ bootCodeData = read_boot_code_data(argv[0]); #else image_info info; if (find_own_image(&info) == B_OK) bootCodeData = read_boot_code_data(info.name); #endif if (!bootCodeData) { fprintf(stderr, "Error: Failed to read \n"); exit(1); } // iterate through the files and make them bootable status_t error; for (int i = 0; i < fileCount; i++) { const char *fileName = files[i]; BEntry entry; error = entry.SetTo(fileName, true); if (error != B_OK) { fprintf(stderr, "Error: Failed to open \"%s\": %s\n", fileName, strerror(error)); exit(1); } // get stat to check the type of the file struct stat st; error = entry.GetStat(&st); if (error != B_OK) { fprintf(stderr, "Error: Failed to stat \"%s\": %s\n", fileName, strerror(error)); exit(1); } 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)) { #if defined(__BEOS__) || defined(__ANTARES__) // 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; #else (void)info; fprintf(stderr, "Error: Specifying directories not supported " "on this platform!\n"); exit(1); #endif } else if (S_ISREG(st.st_mode)) { // a regular file: fine noPartition = true; } else if (S_ISCHR(st.st_mode)) { // character special: a device or partition under BeOS // or under FreeBSD #if !(defined(__BEOS__) || defined(__ANTARES__)) && !defined(ANTARES_HOST_PLATFORM_FREEBSD) fprintf(stderr, "Error: Character special devices not " "supported on this platform.\n"); exit(1); #endif #ifdef ANTARES_HOST_PLATFORM_FREEBSD // 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; } } // Remove de 's' from 'ad2s2' slice device (partition for DOS // users) to get 'ad2' base device baseNameLen--; 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 + 1); // Don't forget the 's' of slice :) 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 size int64 deviceSize; if (ioctl(baseFD, DIOCGMEDIASIZE, &deviceSize) == -1) { fprintf(stderr, "Error: Failed to get device geometry " "for \"%s\": %s\n", baseDeviceName, strerror(errno)); exit(1); } // parse the partition map // TODO: block size! 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); dump_partition_map(map); exit(1); } if (partition->IsExtended()) { fprintf(stderr, "Error: Partition %d is an extended " "partition.\n", partitionIndex); dump_partition_map(map); exit(1); } partitionOffset = partition->Offset(); } else { // The given device is the base device. We'll write at // offset 0. } #endif // ANTARES_HOST_PLATFORM_FREEBSD } else if (S_ISBLK(st.st_mode)) { // block device: a device or partition under Linux or Darwin #ifdef ANTARES_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 size -- try BLKGETSIZE64, but, if it doesn't // work, fall back to the obsolete HDIO_GETGEO int64 deviceSize; hd_geometry geometry; if (ioctl(baseFD, BLKGETSIZE64, &deviceSize) == 0 && deviceSize > 0) { // looks good } else if (ioctl(baseFD, HDIO_GETGEO, &geometry) == 0) { deviceSize = (int64)geometry.heads * geometry.sectors * geometry.cylinders * 512; } else { fprintf(stderr, "Error: Failed to get device geometry " "for \"%s\": %s\n", baseDeviceName, strerror(errno)); exit(1); } // parse the partition map // TODO: block size! 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); dump_partition_map(map); exit(1); } if (partition->IsExtended()) { fprintf(stderr, "Error: Partition %d is an extended " "partition.\n", partitionIndex); dump_partition_map(map); exit(1); } partitionOffset = partition->Offset(); } else { // The given device is the base device. We'll write at // offset 0. } #elif defined(ANTARES_HOST_PLATFORM_DARWIN) // chop off the trailing number int fileNameLen = strlen(fileName); int baseNameLen = fileNameLen - 2; // get base device name and partition index char baseDeviceName[B_PATH_NAME_LENGTH]; int partitionIndex = atoi(fileName + baseNameLen + 1); 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 size int64 blockSize; int64 blockCount; int64 deviceSize; if (ioctl(baseFD, DKIOCGETBLOCKSIZE, &blockSize) == -1) { fprintf(stderr, "Error: Failed to get block size " "for \"%s\": %s\n", baseDeviceName, strerror(errno)); exit(1); } if (ioctl(baseFD, DKIOCGETBLOCKCOUNT, &blockCount) == -1) { fprintf(stderr, "Error: Failed to get block count " "for \"%s\": %s\n", baseDeviceName, strerror(errno)); exit(1); } deviceSize = blockSize * blockCount; // parse the partition map PartitionMapParser parser(baseFD, 0, deviceSize, blockSize); 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); dump_partition_map(map); exit(1); } if (partition->IsExtended()) { fprintf(stderr, "Error: Partition %d is an extended " "partition.\n", partitionIndex); dump_partition_map(map); exit(1); } partitionOffset = partition->Offset(); #else // partitions are block devices under Antares, but not under BeOS #ifndef __ANTARES__ fprintf(stderr, "Error: Block devices not supported on this " "platform!\n"); exit(1); #endif // __ANTARES__ #endif } else { fprintf(stderr, "Error: File type of \"%s\" is not supported.\n", fileName); exit(1); } // open the file int fd = open(fileName, O_RDWR); if (fd < 0) { fprintf(stderr, "Error: Failed to open \"%s\": %s\n", fileName, strerror(errno)); exit(1); } #if (defined(__BEOS__) || defined(__ANTARES__)) // get a partition info if (!noPartition && strlen(fileName) >= 3 && strncmp("raw", fileName + strlen(fileName) - 3, 3)) { partition_info partitionInfo; if (ioctl(fd, B_GET_PARTITION_INFO, &partitionInfo, sizeof(partitionInfo)) == 0) { partitionOffset = partitionInfo.offset; } else { fprintf(stderr, "Error: Failed to get partition info: %s\n", 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 / 512)); // write the boot code printf("Writing boot code to \"%s\" (partition offset: %" B_PRId64 " bytes, start offset = %" B_PRIdOFF ") " "...\n", fileName, partitionOffset, startOffset); write_boot_code_part(fileName, fd, startOffset, bootCodeData, 0, kFirstBootCodePartSize, dryRun); write_boot_code_part(fileName, fd, startOffset, bootCodeData, kSecondBootCodePartOffset, kSecondBootCodePartSize, dryRun); #ifdef __ANTARES__ // check if this partition is mounted BDiskDeviceRoster roster; BPartition* partition; BDiskDevice device; status_t status = roster.GetPartitionForPath(fileName, &device, &partition); if (status != B_OK) { status = roster.GetFileDeviceForPath(fileName, &device); if (status == B_OK) partition = &device; } if (status == B_OK && partition->IsMounted() && !dryRun) { // This partition is mounted, we need to tell BFS to update its // boot block (we are using part of the same logical block). BPath path; status = partition->GetMountPoint(&path); if (status == B_OK) { update_boot_block update; update.offset = kSecondBootCodePartOffset - 512; update.data = bootCodeData + kSecondBootCodePartOffset; update.length = kSecondBootCodePartSize; int mountFD = open(path.Path(), O_RDONLY); if (ioctl(mountFD, BFS_IOCTL_UPDATE_BOOT_BLOCK, &update, sizeof(update_boot_block)) != 0) { fprintf(stderr, "Could not update BFS boot block: %s\n", strerror(errno)); } close(mountFD); } else { fprintf(stderr, "Could not update BFS boot code while the " "partition is mounted!\n"); } } #endif // __ANTARES__ close(fd); } return 0; }