From d11ea2b5edf78d1018b1149a57a593af50687920 Mon Sep 17 00:00:00 2001 From: Ingo Weinhold Date: Sat, 18 Jun 2011 04:23:09 +0200 Subject: [PATCH] Introduce BootVolume abstraction class BootVolume is initialized from a root directory of a volume. It finds the system directory, and -- not implemented yet -- mounts the system package, if the system is packaged, replacing the system directory with it. Adjusted several functionality (main(), the loader functions, user_menu()) to use BootVolume instead of the root directory. --- headers/private/kernel/boot/vfs.h | 32 ++++++++- src/system/boot/loader/loader.cpp | 44 +++++++++--- src/system/boot/loader/loader.h | 6 +- src/system/boot/loader/main.cpp | 23 +++--- src/system/boot/loader/menu.cpp | 8 +-- src/system/boot/loader/menu.h | 3 +- src/system/boot/loader/vfs.cpp | 114 +++++++++++++++++++++++++----- 7 files changed, 182 insertions(+), 48 deletions(-) diff --git a/headers/private/kernel/boot/vfs.h b/headers/private/kernel/boot/vfs.h index b937582ee2..60d7d2bd4e 100644 --- a/headers/private/kernel/boot/vfs.h +++ b/headers/private/kernel/boot/vfs.h @@ -99,11 +99,41 @@ class MemoryDisk : public Node { }; +class BootVolume { +public: + BootVolume(); + ~BootVolume(); + + status_t SetTo(Directory* rootDirectory); + void Unset(); + + bool IsValid() const + { return fRootDirectory != NULL; } + + Directory* RootDirectory() const + { return fRootDirectory; } + Directory* SystemDirectory() const + { return fSystemDirectory; } + bool IsPackaged() const + { return fPackaged; } + +private: + Directory* fRootDirectory; + // root directory of the volume + Directory* fSystemDirectory; + // "system" directory of the volume; if packaged the root + // directory of the mounted packagefs + bool fPackaged; + // indicates whether the boot volume's system is packaged +}; + + /* function prototypes */ extern status_t vfs_init(stage2_args *args); extern status_t register_boot_file_system(Directory *directory); -extern Directory *get_boot_file_system(stage2_args *args); +extern status_t get_boot_file_system(stage2_args* args, + BootVolume& _bootVolume); extern status_t mount_file_systems(stage2_args *args); extern int open_node(Node *node, int mode); extern int open_from(Directory *directory, const char *path, int mode, diff --git a/src/system/boot/loader/loader.cpp b/src/system/boot/loader/loader.cpp index 1137285a16..0436908d33 100644 --- a/src/system/boot/loader/loader.cpp +++ b/src/system/boot/loader/loader.cpp @@ -24,8 +24,12 @@ # error BOOT_ARCH has to be defined to differentiate the kernel per platform #endif +#define SYSTEM_DIRECTORY_PREFIX "system/" #define KERNEL_IMAGE "kernel_" BOOT_ARCH -#define KERNEL_PATH "system/" KERNEL_IMAGE +#define KERNEL_PATH SYSTEM_DIRECTORY_PREFIX KERNEL_IMAGE + + +static const char* const kSystemDirectoryPrefix = SYSTEM_DIRECTORY_PREFIX; static const char *sPaths[] = { @@ -38,15 +42,32 @@ static const char *sPaths[] = { }; +static int +open_maybe_packaged(BootVolume& volume, const char* path, int openMode) +{ + if (strncmp(path, kSystemDirectoryPrefix, strlen(kSystemDirectoryPrefix)) + == 0) { + path += strlen(kSystemDirectoryPrefix); + return open_from(volume.SystemDirectory(), path, openMode); + } + + return open_from(volume.RootDirectory(), path, openMode); +} + + bool is_bootable(Directory *volume) { if (volume->IsEmpty()) return false; + BootVolume bootVolume; + if (bootVolume.SetTo(volume) != B_OK) + return false; + // check for the existance of a kernel (for our platform) - int fd = open_from(volume, KERNEL_PATH, O_RDONLY); - if (fd < B_OK) + int fd = open_maybe_packaged(bootVolume, KERNEL_PATH, O_RDONLY); + if (fd < 0) return false; close(fd); @@ -56,9 +77,9 @@ is_bootable(Directory *volume) status_t -load_kernel(stage2_args *args, Directory *volume) +load_kernel(stage2_args* args, BootVolume& volume) { - int fd = open_from(volume, KERNEL_PATH, O_RDONLY); + int fd = open_maybe_packaged(volume, KERNEL_PATH, O_RDONLY); if (fd < B_OK) return fd; @@ -87,11 +108,11 @@ load_kernel(stage2_args *args, Directory *volume) static status_t -load_modules_from(Directory *volume, const char *path) +load_modules_from(BootVolume& volume, const char* path) { // we don't have readdir() & co. (yet?)... - int fd = open_from(volume, path, O_RDONLY); + int fd = open_maybe_packaged(volume, path, O_RDONLY); if (fd < B_OK) return fd; @@ -125,7 +146,7 @@ load_modules_from(Directory *volume, const char *path) */ static status_t -load_module(Directory *volume, const char *name) +load_module(BootVolume& volume, const char* name) { char moduleName[B_FILE_NAME_LENGTH]; if (strlcpy(moduleName, name, sizeof(moduleName)) > sizeof(moduleName)) @@ -133,7 +154,7 @@ load_module(Directory *volume, const char *name) for (int32 i = 0; sPaths[i]; i++) { // get base path - int baseFD = open_from(volume, sPaths[i], O_RDONLY); + int baseFD = open_maybe_packaged(volume, sPaths[i], O_RDONLY); if (baseFD < B_OK) continue; @@ -174,7 +195,7 @@ load_module(Directory *volume, const char *name) status_t -load_modules(stage2_args *args, Directory *volume) +load_modules(stage2_args* args, BootVolume& volume) { int32 failed = 0; @@ -209,7 +230,8 @@ load_modules(stage2_args *args, Directory *volume) false)) { // iterate over the mounted volumes and load their file system Partition *partition; - if (gRoot->GetPartitionFor(volume, &partition) == B_OK) { + if (gRoot->GetPartitionFor(volume.RootDirectory(), &partition) + == B_OK) { while (partition != NULL) { load_module(volume, partition->ModuleName()); partition = partition->Parent(); diff --git a/src/system/boot/loader/loader.h b/src/system/boot/loader/loader.h index 126eec875a..ea441f3a34 100644 --- a/src/system/boot/loader/loader.h +++ b/src/system/boot/loader/loader.h @@ -9,8 +9,8 @@ #include -extern bool is_bootable(Directory *volume); -extern status_t load_kernel(stage2_args *args, Directory *volume); -extern status_t load_modules(stage2_args *args, Directory *volume); +extern bool is_bootable(Directory* volume); +extern status_t load_kernel(stage2_args* args, BootVolume& volume); +extern status_t load_modules(stage2_args* args, BootVolume& volume); #endif /* LOADER_H */ diff --git a/src/system/boot/loader/main.cpp b/src/system/boot/loader/main.cpp index bc67e3a9ab..309df34cd5 100644 --- a/src/system/boot/loader/main.cpp +++ b/src/system/boot/loader/main.cpp @@ -57,10 +57,11 @@ main(stage2_args *args) bool mountedAllVolumes = false; - Directory *volume = get_boot_file_system(args); + BootVolume bootVolume; - if (volume == NULL || (platform_boot_options() & BOOT_OPTION_MENU) != 0) { - if (volume == NULL) + if (get_boot_file_system(args, bootVolume) != B_OK + || (platform_boot_options() & BOOT_OPTION_MENU) != 0) { + if (!bootVolume.IsValid()) puts("\tno boot path found, scan for all partitions...\n"); if (mount_file_systems(args) < B_OK) { @@ -73,19 +74,19 @@ main(stage2_args *args) mountedAllVolumes = true; - if (user_menu(&volume) < B_OK) { + if (user_menu(bootVolume) < B_OK) { // user requested to quit the loader goto out; } } - if (volume != NULL) { + if (bootVolume.IsValid()) { // we got a volume to boot from! status_t status; - while ((status = load_kernel(args, volume)) < B_OK) { + while ((status = load_kernel(args, bootVolume)) < B_OK) { // loading the kernel failed, so let the user choose another // volume to boot from until it works - volume = NULL; + bootVolume.Unset(); if (!mountedAllVolumes) { // mount all other file systems, if not already happened @@ -95,7 +96,7 @@ main(stage2_args *args) mountedAllVolumes = true; } - if (user_menu(&volume) < B_OK || volume == NULL) { + if (user_menu(bootVolume) < B_OK || !bootVolume.IsValid()) { // user requested to quit the loader goto out; } @@ -105,13 +106,13 @@ main(stage2_args *args) // is already loaded at this point and we definitely // know our boot volume, too if (status == B_OK) { - register_boot_file_system(volume); + register_boot_file_system(bootVolume.RootDirectory()); if ((platform_boot_options() & BOOT_OPTION_DEBUG_OUTPUT) == 0) platform_switch_to_logo(); - load_modules(args, volume); - load_driver_settings(args, volume); + load_modules(args, bootVolume); + load_driver_settings(args, bootVolume.RootDirectory()); // apply boot settings apply_boot_settings(); diff --git a/src/system/boot/loader/menu.cpp b/src/system/boot/loader/menu.cpp index 3c2ae22df8..b2c8c19cfc 100644 --- a/src/system/boot/loader/menu.cpp +++ b/src/system/boot/loader/menu.cpp @@ -960,7 +960,7 @@ user_menu_reboot(Menu* menu, MenuItem* item) status_t -user_menu(Directory** _bootVolume) +user_menu(BootVolume& _bootVolume) { Menu* menu = new(std::nothrow) Menu(MAIN_MENU); Menu* safeModeMenu = NULL; @@ -973,7 +973,7 @@ user_menu(Directory** _bootVolume) // Add boot volume menu->AddItem(item = new(std::nothrow) MenuItem("Select boot volume", - add_boot_volume_menu(*_bootVolume))); + add_boot_volume_menu(_bootVolume.RootDirectory()))); // Add safe mode menu->AddItem(item = new(std::nothrow) MenuItem("Select safe mode options", @@ -993,7 +993,7 @@ user_menu(Directory** _bootVolume) item->SetShortcut('r'); menu->AddItem(item = new(std::nothrow) MenuItem("Continue booting")); - if (*_bootVolume == NULL) { + if (!_bootVolume.IsValid()) { item->SetEnabled(false); menu->ItemAt(0)->Select(true); } else @@ -1003,7 +1003,7 @@ user_menu(Directory** _bootVolume) // See if a new boot device has been selected, and propagate that back if (item->Data() != NULL) - *_bootVolume = (Directory*)item->Data(); + _bootVolume.SetTo((Directory*)item->Data()); apply_safe_mode_options(safeModeMenu); apply_safe_mode_options(debugMenu); diff --git a/src/system/boot/loader/menu.h b/src/system/boot/loader/menu.h index b6343e21ff..a400952fd1 100644 --- a/src/system/boot/loader/menu.h +++ b/src/system/boot/loader/menu.h @@ -9,6 +9,7 @@ #include -extern status_t user_menu(Directory **_bootVolume); +extern status_t user_menu(BootVolume& _bootVolume); + #endif /* MENU_H */ diff --git a/src/system/boot/loader/vfs.cpp b/src/system/boot/loader/vfs.cpp index 2d532309c0..188df09b95 100644 --- a/src/system/boot/loader/vfs.cpp +++ b/src/system/boot/loader/vfs.cpp @@ -357,6 +357,77 @@ Descriptor::Release() // #pragma mark - +BootVolume::BootVolume() + : + fRootDirectory(NULL), + fSystemDirectory(NULL), + fPackaged(false) +{ +} + + +BootVolume::~BootVolume() +{ + Unset(); +} + + +status_t +BootVolume::SetTo(Directory* rootDirectory) +{ + Unset(); + + if (rootDirectory == NULL) + return B_BAD_VALUE; + + fRootDirectory = rootDirectory; + + // find the system directory + Node* systemNode = fRootDirectory->Lookup("system", true); + if (systemNode == NULL || !S_ISDIR(systemNode->Type())) { + if (systemNode != NULL) + systemNode->Release(); + Unset(); + return B_ENTRY_NOT_FOUND; + } + + fSystemDirectory = static_cast(systemNode); + + // check, if the system is packaged + int packageFD = open_from(fSystemDirectory, , + O_RDONLY); + fPackaged = packageFD >= 0; + if (!fPackaged) + return B_OK; + + // the system is packaged -- mount the packagefs +// TODO:... +Unset(); +dprintf("BootVolume::SetTo(): packagefs not supported yet!\n"); +return B_NOT_SUPPORTED; +} + + +void +BootVolume::Unset() +{ + if (fRootDirectory != NULL) { + fRootDirectory->Release(); + fRootDirectory = NULL; + } + + if (fSystemDirectory != NULL) { + fSystemDirectory->Release(); + fSystemDirectory = NULL; + } + + fPackaged = false; +} + + +// #pragma mark - + + status_t vfs_init(stage2_args *args) { @@ -393,41 +464,50 @@ register_boot_file_system(Directory *volume) } -/** Gets the boot device, scans all of its partitions, gets the - * boot partition, and mounts its file system. - * Returns the file system's root node or NULL for failure. - */ +/*! Gets the boot device, scans all of its partitions, gets the + boot partition, and mounts its file system. -Directory * -get_boot_file_system(stage2_args *args) + \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) { Node *device; - if (platform_add_boot_device(args, &gBootDevices) < B_OK) - return NULL; + status_t error = platform_add_boot_device(args, &gBootDevices); + if (error != B_OK) + return error; // the boot device must be the first device in the list device = gBootDevices.First(); - if (add_partitions_for(device, false, true) < B_OK) - return NULL; + error = add_partitions_for(device, false, true); + if (error != B_OK) + return error; Partition *partition; - if (platform_get_boot_partition(args, device, &gPartitions, &partition) < B_OK) - return NULL; + error = platform_get_boot_partition(args, device, &gPartitions, &partition); + if (error != B_OK) + return error; Directory *fileSystem; - status_t status = partition->Mount(&fileSystem, true); - - if (status < B_OK) { + 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; - return NULL; + return error; } + // init the BootVolume + error = _bootVolume.SetTo(fileSystem); + if (error != B_OK) + return error; + sBootDevice = device; - return fileSystem; + return B_OK; }