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.
This commit is contained in:
Ingo Weinhold
2011-07-17 16:54:13 +02:00
parent 624b7c8958
commit d11ea2b5ed
7 changed files with 182 additions and 48 deletions
+31 -1
View File
@@ -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 */ /* function prototypes */
extern status_t vfs_init(stage2_args *args); extern status_t vfs_init(stage2_args *args);
extern status_t register_boot_file_system(Directory *directory); 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 status_t mount_file_systems(stage2_args *args);
extern int open_node(Node *node, int mode); extern int open_node(Node *node, int mode);
extern int open_from(Directory *directory, const char *path, int mode, extern int open_from(Directory *directory, const char *path, int mode,
+33 -11
View File
@@ -24,8 +24,12 @@
# error BOOT_ARCH has to be defined to differentiate the kernel per platform # error BOOT_ARCH has to be defined to differentiate the kernel per platform
#endif #endif
#define SYSTEM_DIRECTORY_PREFIX "system/"
#define KERNEL_IMAGE "kernel_" BOOT_ARCH #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[] = { 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 bool
is_bootable(Directory *volume) is_bootable(Directory *volume)
{ {
if (volume->IsEmpty()) if (volume->IsEmpty())
return false; return false;
BootVolume bootVolume;
if (bootVolume.SetTo(volume) != B_OK)
return false;
// check for the existance of a kernel (for our platform) // check for the existance of a kernel (for our platform)
int fd = open_from(volume, KERNEL_PATH, O_RDONLY); int fd = open_maybe_packaged(bootVolume, KERNEL_PATH, O_RDONLY);
if (fd < B_OK) if (fd < 0)
return false; return false;
close(fd); close(fd);
@@ -56,9 +77,9 @@ is_bootable(Directory *volume)
status_t 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) if (fd < B_OK)
return fd; return fd;
@@ -87,11 +108,11 @@ load_kernel(stage2_args *args, Directory *volume)
static status_t 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?)... // 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) if (fd < B_OK)
return fd; return fd;
@@ -125,7 +146,7 @@ load_modules_from(Directory *volume, const char *path)
*/ */
static status_t static status_t
load_module(Directory *volume, const char *name) load_module(BootVolume& volume, const char* name)
{ {
char moduleName[B_FILE_NAME_LENGTH]; char moduleName[B_FILE_NAME_LENGTH];
if (strlcpy(moduleName, name, sizeof(moduleName)) > sizeof(moduleName)) 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++) { for (int32 i = 0; sPaths[i]; i++) {
// get base path // 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) if (baseFD < B_OK)
continue; continue;
@@ -174,7 +195,7 @@ load_module(Directory *volume, const char *name)
status_t status_t
load_modules(stage2_args *args, Directory *volume) load_modules(stage2_args* args, BootVolume& volume)
{ {
int32 failed = 0; int32 failed = 0;
@@ -209,7 +230,8 @@ load_modules(stage2_args *args, Directory *volume)
false)) { false)) {
// iterate over the mounted volumes and load their file system // iterate over the mounted volumes and load their file system
Partition *partition; Partition *partition;
if (gRoot->GetPartitionFor(volume, &partition) == B_OK) { if (gRoot->GetPartitionFor(volume.RootDirectory(), &partition)
== B_OK) {
while (partition != NULL) { while (partition != NULL) {
load_module(volume, partition->ModuleName()); load_module(volume, partition->ModuleName());
partition = partition->Parent(); partition = partition->Parent();
+3 -3
View File
@@ -9,8 +9,8 @@
#include <boot/vfs.h> #include <boot/vfs.h>
extern bool is_bootable(Directory *volume); extern bool is_bootable(Directory* volume);
extern status_t load_kernel(stage2_args *args, Directory *volume); extern status_t load_kernel(stage2_args* args, BootVolume& volume);
extern status_t load_modules(stage2_args *args, Directory *volume); extern status_t load_modules(stage2_args* args, BootVolume& volume);
#endif /* LOADER_H */ #endif /* LOADER_H */
+12 -11
View File
@@ -57,10 +57,11 @@ main(stage2_args *args)
bool mountedAllVolumes = false; bool mountedAllVolumes = false;
Directory *volume = get_boot_file_system(args); BootVolume bootVolume;
if (volume == NULL || (platform_boot_options() & BOOT_OPTION_MENU) != 0) { if (get_boot_file_system(args, bootVolume) != B_OK
if (volume == NULL) || (platform_boot_options() & BOOT_OPTION_MENU) != 0) {
if (!bootVolume.IsValid())
puts("\tno boot path found, scan for all partitions...\n"); puts("\tno boot path found, scan for all partitions...\n");
if (mount_file_systems(args) < B_OK) { if (mount_file_systems(args) < B_OK) {
@@ -73,19 +74,19 @@ main(stage2_args *args)
mountedAllVolumes = true; mountedAllVolumes = true;
if (user_menu(&volume) < B_OK) { if (user_menu(bootVolume) < B_OK) {
// user requested to quit the loader // user requested to quit the loader
goto out; goto out;
} }
} }
if (volume != NULL) { if (bootVolume.IsValid()) {
// we got a volume to boot from! // we got a volume to boot from!
status_t status; 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 // loading the kernel failed, so let the user choose another
// volume to boot from until it works // volume to boot from until it works
volume = NULL; bootVolume.Unset();
if (!mountedAllVolumes) { if (!mountedAllVolumes) {
// mount all other file systems, if not already happened // mount all other file systems, if not already happened
@@ -95,7 +96,7 @@ main(stage2_args *args)
mountedAllVolumes = true; mountedAllVolumes = true;
} }
if (user_menu(&volume) < B_OK || volume == NULL) { if (user_menu(bootVolume) < B_OK || !bootVolume.IsValid()) {
// user requested to quit the loader // user requested to quit the loader
goto out; goto out;
} }
@@ -105,13 +106,13 @@ main(stage2_args *args)
// is already loaded at this point and we definitely // is already loaded at this point and we definitely
// know our boot volume, too // know our boot volume, too
if (status == B_OK) { if (status == B_OK) {
register_boot_file_system(volume); register_boot_file_system(bootVolume.RootDirectory());
if ((platform_boot_options() & BOOT_OPTION_DEBUG_OUTPUT) == 0) if ((platform_boot_options() & BOOT_OPTION_DEBUG_OUTPUT) == 0)
platform_switch_to_logo(); platform_switch_to_logo();
load_modules(args, volume); load_modules(args, bootVolume);
load_driver_settings(args, volume); load_driver_settings(args, bootVolume.RootDirectory());
// apply boot settings // apply boot settings
apply_boot_settings(); apply_boot_settings();
+4 -4
View File
@@ -960,7 +960,7 @@ user_menu_reboot(Menu* menu, MenuItem* item)
status_t status_t
user_menu(Directory** _bootVolume) user_menu(BootVolume& _bootVolume)
{ {
Menu* menu = new(std::nothrow) Menu(MAIN_MENU); Menu* menu = new(std::nothrow) Menu(MAIN_MENU);
Menu* safeModeMenu = NULL; Menu* safeModeMenu = NULL;
@@ -973,7 +973,7 @@ user_menu(Directory** _bootVolume)
// Add boot volume // Add boot volume
menu->AddItem(item = new(std::nothrow) MenuItem("Select 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 // Add safe mode
menu->AddItem(item = new(std::nothrow) MenuItem("Select safe mode options", menu->AddItem(item = new(std::nothrow) MenuItem("Select safe mode options",
@@ -993,7 +993,7 @@ user_menu(Directory** _bootVolume)
item->SetShortcut('r'); item->SetShortcut('r');
menu->AddItem(item = new(std::nothrow) MenuItem("Continue booting")); menu->AddItem(item = new(std::nothrow) MenuItem("Continue booting"));
if (*_bootVolume == NULL) { if (!_bootVolume.IsValid()) {
item->SetEnabled(false); item->SetEnabled(false);
menu->ItemAt(0)->Select(true); menu->ItemAt(0)->Select(true);
} else } else
@@ -1003,7 +1003,7 @@ user_menu(Directory** _bootVolume)
// See if a new boot device has been selected, and propagate that back // See if a new boot device has been selected, and propagate that back
if (item->Data() != NULL) if (item->Data() != NULL)
*_bootVolume = (Directory*)item->Data(); _bootVolume.SetTo((Directory*)item->Data());
apply_safe_mode_options(safeModeMenu); apply_safe_mode_options(safeModeMenu);
apply_safe_mode_options(debugMenu); apply_safe_mode_options(debugMenu);
+2 -1
View File
@@ -9,6 +9,7 @@
#include <boot/vfs.h> #include <boot/vfs.h>
extern status_t user_menu(Directory **_bootVolume); extern status_t user_menu(BootVolume& _bootVolume);
#endif /* MENU_H */ #endif /* MENU_H */
+97 -17
View File
@@ -357,6 +357,77 @@ Descriptor::Release()
// #pragma mark - // #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<Directory*>(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 status_t
vfs_init(stage2_args *args) 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 /*! Gets the boot device, scans all of its partitions, gets the
* boot partition, and mounts its file system. boot partition, and mounts its file system.
* Returns the file system's root node or NULL for failure.
*/
Directory * \param args The stage 2 arguments.
get_boot_file_system(stage2_args *args) \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; Node *device;
if (platform_add_boot_device(args, &gBootDevices) < B_OK) status_t error = platform_add_boot_device(args, &gBootDevices);
return NULL; if (error != B_OK)
return error;
// the boot device must be the first device in the list // the boot device must be the first device in the list
device = gBootDevices.First(); device = gBootDevices.First();
if (add_partitions_for(device, false, true) < B_OK) error = add_partitions_for(device, false, true);
return NULL; if (error != B_OK)
return error;
Partition *partition; Partition *partition;
if (platform_get_boot_partition(args, device, &gPartitions, &partition) < B_OK) error = platform_get_boot_partition(args, device, &gPartitions, &partition);
return NULL; if (error != B_OK)
return error;
Directory *fileSystem; Directory *fileSystem;
status_t status = partition->Mount(&fileSystem, true); error = partition->Mount(&fileSystem, true);
if (error != B_OK) {
if (status < B_OK) {
// this partition doesn't contain any known file system; we // this partition doesn't contain any known file system; we
// don't need it anymore // don't need it anymore
gPartitions.Remove(partition); gPartitions.Remove(partition);
delete partition; delete partition;
return NULL; return error;
} }
// init the BootVolume
error = _bootVolume.SetTo(fileSystem);
if (error != B_OK)
return error;
sBootDevice = device; sBootDevice = device;
return fileSystem; return B_OK;
} }