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 */
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,
+33 -11
View File
@@ -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();
+3 -3
View File
@@ -9,8 +9,8 @@
#include <boot/vfs.h>
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 */
+12 -11
View File
@@ -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();
+4 -4
View File
@@ -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);
+2 -1
View File
@@ -9,6 +9,7 @@
#include <boot/vfs.h>
extern status_t user_menu(Directory **_bootVolume);
extern status_t user_menu(BootVolume& _bootVolume);
#endif /* MENU_H */
+97 -17
View File
@@ -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<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
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;
}