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:
@@ -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,
|
||||
|
||||
@@ -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();
|
||||
|
||||
@@ -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 */
|
||||
|
||||
@@ -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();
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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 */
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
|
||||
|
||||
Reference in New Issue
Block a user