/*! Gets the boot device, scans all of its partitions, gets the boot partition, and mounts its file system. \param args The stage 2 arguments. \param _bootVolume On success set to the boot volume. \return \c B_OK on success, another error code otherwise. */ status_t get_boot_file_system(stage2_args* args, BootVolume& _bootVolume) { status_t error = platform_add_boot_device(args, &gBootDevices); if (error != B_OK) return error; NodeIterator iterator = gBootDevices.GetIterator(); while (iterator.HasNext()) { Node *device = iterator.Next(); error = add_partitions_for(device, false, true); if (error != B_OK) continue; NodeList bootPartitions; error = platform_get_boot_partitions(args, device, &gPartitions, &bootPartitions); if (error != B_OK) continue; NodeIterator partitionIterator = bootPartitions.GetIterator(); while (partitionIterator.HasNext()) { Partition *partition = (Partition*)partitionIterator.Next(); Directory *fileSystem; error = partition->Mount(&fileSystem, true); if (error != B_OK) { // this partition doesn't contain any known file system; we // don't need it anymore gPartitions.Remove(partition); delete partition; continue; } // init the BootVolume error = _bootVolume.SetTo(fileSystem); if (error != B_OK) continue; sBootDevice = device; return B_OK; } } return B_ERROR; }
status_t platform_get_boot_partition(struct stage2_args *args, Node *device, NodeList *list, boot::Partition **_partition) { NodeIterator iterator = list->GetIterator(); boot::Partition *partition = NULL; while ((partition = (boot::Partition *)iterator.Next()) != NULL) { // ToDo: just take the first partition for now *_partition = partition; return B_OK; } return B_ENTRY_NOT_FOUND; }
Partition::~Partition() { TRACE(("%p Partition::~Partition\n", this)); // Tell the children that their parent is gone NodeIterator iterator = gPartitions.GetIterator(); Partition *child; while ((child = (Partition *)iterator.Next()) != NULL) { if (child->Parent() == this) child->SetParent(NULL); } close(fFD); }
status_t mount_file_systems(stage2_args *args) { // mount other partitions on boot device (if any) NodeIterator iterator = gPartitions.GetIterator(); Partition *partition = NULL; while ((partition = (Partition *)iterator.Next()) != NULL) { // don't scan known partitions again if (partition->IsFileSystem()) continue; // remove the partition if it doesn't contain a (known) file system if (partition->Scan(true) != B_OK && !partition->IsFileSystem()) { gPartitions.Remove(partition); delete partition; } } // add all block devices the platform has for us status_t status = platform_add_block_devices(args, &gBootDevices); if (status < B_OK) return status; iterator = gBootDevices.GetIterator(); Node *device = NULL, *last = NULL; while ((device = iterator.Next()) != NULL) { // don't scan former boot device again if (device == sBootDevice) continue; if (add_partitions_for(device, true) == B_OK) { // ToDo: we can't delete the object here, because it must // be removed from the list before we know that it was // deleted. /* // if the Release() deletes the object, we need to skip it if (device->Release() > 0) { list_remove_item(&gBootDevices, device); device = last; } */ (void)last; } last = device; } if (gPartitions.IsEmpty()) return B_ENTRY_NOT_FOUND; #if 0 void *cookie; if (gRoot->Open(&cookie, O_RDONLY) == B_OK) { Directory *directory; while (gRoot->GetNextNode(cookie, (Node **)&directory) == B_OK) { char name[256]; if (directory->GetName(name, sizeof(name)) == B_OK) printf(":: %s (%p)\n", name, directory); void *subCookie; if (directory->Open(&subCookie, O_RDONLY) == B_OK) { while (directory->GetNextEntry(subCookie, name, sizeof(name)) == B_OK) { printf("\t%s\n", name); } directory->Close(subCookie); } } gRoot->Close(cookie); } #endif return B_OK; }
status_t Partition::Scan(bool mountFileSystems, bool isBootDevice) { // scan for partitions first (recursively all eventual children as well) TRACE(("%p Partition::Scan()\n", this)); // if we were not booted from the real boot device, we won't scan // the device we were booted from (which is likely to be a slow // floppy or CD) if (isBootDevice && gKernelArgs.boot_volume.GetBool( BOOT_VOLUME_BOOTED_FROM_IMAGE, false)) { return B_ENTRY_NOT_FOUND; } const partition_module_info *bestModule = NULL; void *bestCookie = NULL; float bestPriority = -1; for (int32 i = 0; i < sNumPartitionModules; i++) { const partition_module_info *module = sPartitionModules[i]; void *cookie = NULL; NodeOpener opener(this, O_RDONLY); TRACE(("check for partitioning_system: %s\n", module->pretty_name)); float priority = module->identify_partition(opener.Descriptor(), this, &cookie); if (priority < 0.0) continue; TRACE((" priority: %ld\n", (int32)(priority * 1000))); if (priority <= bestPriority) { // the disk system recognized the partition worse than the currently // best one module->free_identify_partition_cookie(this, cookie); continue; } // a new winner, replace the previous one if (bestModule) bestModule->free_identify_partition_cookie(this, bestCookie); bestModule = module; bestCookie = cookie; bestPriority = priority; } // find the best FS module const file_system_module_info *bestFSModule = NULL; float bestFSPriority = -1; for (int32 i = 0; i < sNumFileSystemModules; i++) { if (sFileSystemModules[i]->identify_file_system == NULL) continue; float priority = sFileSystemModules[i]->identify_file_system(this); if (priority <= 0) continue; if (priority > bestFSPriority) { bestFSModule = sFileSystemModules[i]; bestFSPriority = priority; } } // now let the best matching disk system scan the partition if (bestModule && bestPriority >= bestFSPriority) { NodeOpener opener(this, O_RDONLY); status_t status = bestModule->scan_partition(opener.Descriptor(), this, bestCookie); bestModule->free_identify_partition_cookie(this, bestCookie); if (status != B_OK) { dprintf("Partitioning module `%s' recognized the partition, but " "failed to scan it\n", bestModule->pretty_name); return status; } fIsPartitioningSystem = true; content_type = bestModule->pretty_name; flags |= B_PARTITION_PARTITIONING_SYSTEM; // now that we've found something, check our children // out as well! NodeIterator iterator = fChildren.GetIterator(); Partition *child = NULL; while ((child = (Partition *)iterator.Next()) != NULL) { TRACE(("%p Partition::Scan(): scan child %p (start = %Ld, size " "= %Ld, parent = %p)!\n", this, child, child->offset, child->size, child->Parent())); child->Scan(mountFileSystems); if (!mountFileSystems || child->IsFileSystem()) { // move the partitions containing file systems to the partition // list fChildren.Remove(child); gPartitions.Add(child); } } // remove all unused children (we keep only file systems) while ((child = (Partition *)fChildren.Head()) != NULL) { fChildren.Remove(child); delete child; } // remember the name of the module that identified us fModuleName = bestModule->module.name; return B_OK; } // scan for file systems if (mountFileSystems) { // TODO: Use the FS module we've got, if any. Requires to implement the // identify_file_system() hook in every FS. return Mount(); } return B_ENTRY_NOT_FOUND; }