boot loader: Add safe mode blacklist submenu

It's a browser for the system package content, where entries can be
selected to blacklist them. The selected entries are removed from the
packagefs instance in the boot loader, so that e.g. selected drivers
won't be picked up. The paths are also added to the safe mode driver
settings and will be interpreted when the system packagefs instance is
mounted by the kernel.
This commit is contained in:
Ingo Weinhold 2013-11-20 15:59:46 +01:00
parent f2620e4714
commit c04f3a625a
10 changed files with 785 additions and 61 deletions

View File

@ -0,0 +1,72 @@
/*
* Copyright 2013, Ingo Weinhold, ingo_weinhold@gmx.de.
* Distributed under the terms of the MIT License.
*/
#ifndef KERNEL_BOOT_PATH_BLACKLIST_H
#define KERNEL_BOOT_PATH_BLACKLIST_H
#include <string.h>
#include <util/SinglyLinkedList.h>
class BlacklistedPath : public SinglyLinkedListLinkImpl<BlacklistedPath> {
public:
BlacklistedPath();
~BlacklistedPath();
bool SetTo(const char* path);
bool Append(const char* component);
const char* Path() const
{ return fPath != NULL ? fPath : ""; }
size_t Length() const
{ return fLength; }
bool operator==(const char* path) const
{ return strcmp(Path(), path) == 0; }
private:
bool _Resize(size_t length, bool keepData);
private:
char* fPath;
size_t fLength;
size_t fCapacity;
};
class PathBlacklist {
public:
typedef SinglyLinkedList<BlacklistedPath>::Iterator Iterator;
public:
PathBlacklist();
~PathBlacklist();
bool Add(const char* path);
void Remove(const char* path);
bool Contains(const char* path) const;
void MakeEmpty();
bool IsEmpty() const
{ return fPaths.IsEmpty(); }
Iterator GetIterator() const
{ return fPaths.GetIterator(); }
private:
BlacklistedPath* _FindPath(const char* path) const;
private:
typedef SinglyLinkedList<BlacklistedPath> PathList;
private:
PathList fPaths;
};
#endif // KERNEL_BOOT_PATH_BLACKLIST_H

View File

@ -16,6 +16,9 @@
#include "DebugSupport.h"
static const char* const kEntryBlacklistParameterName = "EntryBlacklist";
// #pragma mark - PackageSettingsItem
@ -39,14 +42,21 @@ PackageSettingsItem::~PackageSettingsItem()
status_t
PackageSettingsItem::Init(const driver_parameter& parameter)
PackageSettingsItem::Init(const char* name)
{
if (!fName.SetTo(parameter.values[0]) || fEntries.Init() != B_OK)
if (!fName.SetTo(name) || fEntries.Init() != B_OK)
RETURN_ERROR(B_NO_MEMORY);
return B_OK;
}
for (int i = 0; i < parameter.parameter_count; i++) {
const driver_parameter& subParameter = parameter.parameters[i];
if (strcmp(subParameter.name, "EntryBlacklist") != 0)
status_t
PackageSettingsItem::ApplySettings(const driver_parameter* parameters,
int parameterCount)
{
for (int i = 0; i < parameterCount; i++) {
const driver_parameter& subParameter = parameters[i];
if (strcmp(subParameter.name, kEntryBlacklistParameterName) != 0)
continue;
status_t error = _AddBlackListedEntries(subParameter);
@ -165,6 +175,22 @@ PackageSettings::Load(dev_t mountPointDeviceID, ino_t mountPointNodeID,
if (error != B_OK)
RETURN_ERROR(error);
// First get the safe mode options. Those apply to the system package.
if (mountType == PACKAGE_FS_MOUNT_TYPE_SYSTEM) {
void* settingsHandle = load_driver_settings(B_SAFEMODE_DRIVER_SETTINGS);
if (settingsHandle != NULL) {
if (const driver_settings* settings
= get_driver_settings(settingsHandle)) {
error = _AddPackageSettingsItem("haiku", settings->parameters,
settings->parameter_count);
// abort only in case of serious issues (memory shortage)
if (error == B_NO_MEMORY)
return error;
}
unload_driver_settings(settingsHandle);
}
}
// get the mount point relative settings file path
const char* settingsFilePath = mountType == PACKAGE_FS_MOUNT_TYPE_HOME
? kUserSettingsGlobalDirectory "/packages"
@ -201,7 +227,8 @@ PackageSettings::Load(dev_t mountPointDeviceID, ino_t mountPointNodeID,
continue;
}
error = _AddPackageSettingsItem(parameter);
error = _AddPackageSettingsItem(parameter.values[0],
parameter.parameters, parameter.parameter_count);
// abort only in case of serious issues (memory shortage)
if (error == B_NO_MEMORY)
return error;
@ -219,14 +246,21 @@ PackageSettings::PackageItemFor(const String& name) const
status_t
PackageSettings::_AddPackageSettingsItem(const driver_parameter& parameter)
PackageSettings::_AddPackageSettingsItem(const char* name,
const driver_parameter* parameters, int parameterCount)
{
PackageSettingsItem* packageItem = new(std::nothrow) PackageSettingsItem;
if (packageItem == NULL || packageItem->Init(parameter) != B_OK) {
delete packageItem;
RETURN_ERROR(B_NO_MEMORY);
// get/create the package item
PackageSettingsItem* packageItem = fPackageItems.Lookup(StringKey(name));
if (packageItem == NULL) {
packageItem = new(std::nothrow) PackageSettingsItem;
if (packageItem == NULL || packageItem->Init(name) != B_OK) {
delete packageItem;
RETURN_ERROR(B_NO_MEMORY);
}
fPackageItems.Insert(packageItem);
}
fPackageItems.Insert(packageItem);
return B_OK;
// apply the settings
return packageItem->ApplySettings(parameters, parameterCount);
}

View File

@ -9,7 +9,7 @@
#include <packagefs.h>
#include <util/OpenHashTable.h>
#include "String.h"
#include "StringKey.h"
struct driver_parameter;
@ -102,7 +102,10 @@ public:
PackageSettingsItem();
~PackageSettingsItem();
status_t Init(const driver_parameter& parameter);
status_t Init(const char* name);
status_t ApplySettings(
const driver_parameter* parameters,
int parameterCount);
const String& Name() const
{ return fName; }
@ -158,10 +161,10 @@ private:
struct PackageSettingsItemHashDefinition {
typedef String KeyType;
typedef StringKey KeyType;
typedef PackageSettingsItem ValueType;
size_t HashKey(const String& key) const
size_t HashKey(const StringKey& key) const
{
return key.Hash();
}
@ -171,7 +174,7 @@ struct PackageSettingsItemHashDefinition {
return HashKey(value->Name());
}
bool Compare(const String& key, const PackageSettingsItem* value) const
bool Compare(const StringKey& key, const PackageSettingsItem* value) const
{
return key == value->Name();
}
@ -199,8 +202,9 @@ private:
PackageItemTable;
private:
status_t _AddPackageSettingsItem(
const driver_parameter& parameter);
status_t _AddPackageSettingsItem(const char* name,
const driver_parameter* parameters,
int parameterCount);
private:
PackageItemTable fPackageItems;

View File

@ -56,6 +56,7 @@ UsePrivateHeaders shared storage ;
BootStaticLibrary boot_loader :
PathBlacklist.cpp
elf.cpp
heap.cpp
kernel_args.cpp

View File

@ -0,0 +1,180 @@
/*
* Copyright 2013, Ingo Weinhold, ingo_weinhold@gmx.de.
* Distributed under the terms of the MIT License.
*/
#include <boot/PathBlacklist.h>
#include <stdlib.h>
#include <algorithm>
// #pragma mark - BlacklistedPath
BlacklistedPath::BlacklistedPath()
:
fPath(NULL),
fLength(0),
fCapacity(0)
{
}
BlacklistedPath::~BlacklistedPath()
{
free(fPath);
}
bool
BlacklistedPath::SetTo(const char* path)
{
size_t length = strlen(path);
if (length > 0 && path[length - 1] == '/')
length--;
if (!_Resize(length, false))
return false;
if (length > 0) {
memcpy(fPath, path, length);
fPath[length] = '\0';
}
return true;
}
bool
BlacklistedPath::Append(const char* component)
{
size_t componentLength = strlen(component);
if (componentLength > 0 && component[componentLength - 1] == '/')
componentLength--;
if (componentLength == 0)
return true;
size_t oldLength = fLength;
size_t length = (fLength > 0 ? fLength + 1 : 0) + componentLength;
if (!_Resize(length, true))
return false;
if (oldLength > 0)
fPath[oldLength++] = '/';
memcpy(fPath + oldLength, component, componentLength);
return true;
}
bool
BlacklistedPath::_Resize(size_t length, bool keepData)
{
if (length == 0) {
free(fPath);
fPath = NULL;
fLength = 0;
fCapacity = 0;
return true;
}
if (length < fCapacity) {
fPath[length] = '\0';
fLength = length;
return true;
}
size_t capacity = std::max(length + 1, 2 * fCapacity);
capacity = std::max(capacity, size_t(32));
char* path;
if (fLength > 0 && keepData) {
path = (char*)realloc(fPath, capacity);
if (path == NULL)
return false;
} else {
path = (char*)malloc(capacity);
if (path == NULL)
return false;
free(fPath);
}
fPath = path;
fPath[length] = '\0';
fLength = length;
fCapacity = capacity;
return true;
}
// #pragma mark - PathBlacklist
PathBlacklist::PathBlacklist()
{
}
PathBlacklist::~PathBlacklist()
{
MakeEmpty();
}
bool
PathBlacklist::Add(const char* path)
{
BlacklistedPath* blacklistedPath = _FindPath(path);
if (blacklistedPath != NULL)
return true;
blacklistedPath = new(std::nothrow) BlacklistedPath;
if (blacklistedPath == NULL || !blacklistedPath->SetTo(path)) {
delete blacklistedPath;
return false;
}
fPaths.Add(blacklistedPath);
return true;
}
void
PathBlacklist::Remove(const char* path)
{
BlacklistedPath* blacklistedPath = _FindPath(path);
if (blacklistedPath != NULL) {
fPaths.Remove(blacklistedPath);
delete blacklistedPath;
}
}
bool
PathBlacklist::Contains(const char* path) const
{
return _FindPath(path) != NULL;
}
void
PathBlacklist::MakeEmpty()
{
while (BlacklistedPath* blacklistedPath = fPaths.RemoveHead())
delete blacklistedPath;
}
BlacklistedPath*
PathBlacklist::_FindPath(const char* path) const
{
for (PathList::Iterator it = fPaths.GetIterator(); it.HasNext();) {
BlacklistedPath* blacklistedPath = it.Next();
if (*blacklistedPath == path)
return blacklistedPath;
}
return NULL;
}

View File

@ -23,6 +23,7 @@
#include <Referenceable.h>
#include <boot/PathBlacklist.h>
#include <boot/platform.h>
#include "PackageSettingsItem.h"
@ -46,10 +47,10 @@ using namespace BPackageKit::BHPKG;
using BPackageKit::BHPKG::BPrivate::PackageFileHeapReader;
using BPackageKit::BHPKG::BPrivate::PackageReaderImpl;
using PackageFS::PackageSettingsItem;
using namespace PackageFS;
namespace {
namespace PackageFS {
struct PackageDirectory;
@ -120,6 +121,10 @@ struct PackageNode : DoublyLinkedListLinkImpl<PackageNode> {
return fModifiedTime;
}
virtual void RemoveEntry(const char* path)
{
}
protected:
PackageVolume* fVolume;
PackageDirectory* fParentDirectory;
@ -226,18 +231,46 @@ struct PackageDirectory : PackageNode {
if (strcmp(name, "..") == 0)
return fParentDirectory;
for (NodeList::Iterator it = fEntries.GetIterator();
PackageNode* child = it.Next();) {
if (strcmp(child->Name(), name) == 0)
return child;
}
return _LookupChild(name, strlen(name));
}
return NULL;
virtual void RemoveEntry(const char* path)
{
const char* componentEnd = strchr(path, '/');
if (componentEnd == NULL)
componentEnd = path + strlen(path);
PackageNode* child = _LookupChild(path, componentEnd - path);
if (child == NULL)
return;
if (*componentEnd == '\0') {
// last path component -- delete the child
fEntries.Remove(child);
delete child;
} else {
// must be a directory component -- continue resolving the path
child->RemoveEntry(componentEnd + 1);
}
}
private:
typedef DoublyLinkedList<PackageNode> NodeList;
private:
PackageNode* _LookupChild(const char* name, size_t nameLength)
{
for (NodeList::Iterator it = fEntries.GetIterator();
PackageNode* child = it.Next();) {
if (strncmp(child->Name(), name, nameLength) == 0
&& child->Name()[nameLength] == '\0') {
return child;
}
}
return NULL;
}
private:
NodeList fEntries;
};
@ -641,6 +674,11 @@ struct Directory : ::Directory {
fDirectory->Volume()->ReleaseReference();
}
void RemoveEntry(const char* path)
{
fDirectory->RemoveEntry(path);
}
virtual ssize_t ReadAt(void* cookie, off_t pos, void* buffer,
size_t bufferSize)
{
@ -789,7 +827,7 @@ create_node(PackageNode* packageNode, ::Node*& _node)
}
} // unnamed namespace
} // namespace PackageFS
status_t
@ -836,3 +874,18 @@ packagefs_mount_file(int fd, ::Directory* systemDirectory,
_mountedDirectory = static_cast< ::Directory*>(rootNode);
return B_OK;
}
void
packagefs_apply_path_blacklist(::Directory* systemDirectory,
const PathBlacklist& pathBlacklist)
{
PackageFS::Directory* directory
= static_cast<PackageFS::Directory*>(systemDirectory);
for (PathBlacklist::Iterator it = pathBlacklist.GetIterator();
BlacklistedPath* path = it.Next();) {
directory->RemoveEntry(path->Path());
}
}

View File

@ -11,6 +11,7 @@
#include <SupportDefs.h>
class PathBlacklist;
class Directory;
class Node;
@ -18,5 +19,8 @@ class Node;
status_t packagefs_mount_file(int fd, Directory* systemDirectory,
Directory*& _mountedDirectory);
void packagefs_apply_path_blacklist(Directory* systemDirectory,
const PathBlacklist& pathBlacklist);
#endif // BOOT_LOADER_FILE_SYSTEMS_PACKAGEFS_H

View File

@ -12,8 +12,11 @@
#include <boot/vfs.h>
#include <boot/platform.h>
#include <boot/heap.h>
#include <boot/PathBlacklist.h>
#include <boot/stdio.h>
#include "file_systems/packagefs/packagefs.h"
//#define TRACE_MAIN
#ifdef TRACE_MAIN
@ -53,6 +56,7 @@ main(stage2_args *args)
bool mountedAllVolumes = false;
BootVolume bootVolume;
PathBlacklist pathBlacklist;
if (get_boot_file_system(args, bootVolume) != B_OK
|| (platform_boot_options() & BOOT_OPTION_MENU) != 0) {
@ -69,7 +73,7 @@ main(stage2_args *args)
mountedAllVolumes = true;
if (user_menu(bootVolume) < B_OK) {
if (user_menu(bootVolume, pathBlacklist) < B_OK) {
// user requested to quit the loader
goto out;
}
@ -91,7 +95,8 @@ main(stage2_args *args)
mountedAllVolumes = true;
}
if (user_menu(bootVolume) < B_OK || !bootVolume.IsValid()) {
if (user_menu(bootVolume, pathBlacklist) != B_OK
|| !bootVolume.IsValid()) {
// user requested to quit the loader
goto out;
}
@ -101,6 +106,11 @@ main(stage2_args *args)
// is already loaded at this point and we definitely
// know our boot volume, too
if (status == B_OK) {
if (bootVolume.IsPackaged()) {
packagefs_apply_path_blacklist(bootVolume.SystemDirectory(),
pathBlacklist);
}
register_boot_file_system(bootVolume);
if ((platform_boot_options() & BOOT_OPTION_DEBUG_OUTPUT) == 0)

View File

@ -1,6 +1,7 @@
/*
* Copyright 2003-2013, Axel Dörfler, axeld@pinc-software.de.
* Copyright 2011, Rene Gollent, rene@gollent.com.
* Copyright 2013, Ingo Weinhold, ingo_weinhold@gmx.de.
* Distributed under the terms of the MIT License.
*/
@ -14,7 +15,9 @@
#include <OS.h>
#include <AutoDeleter.h>
#include <boot/menu.h>
#include <boot/PathBlacklist.h>
#include <boot/stage2.h>
#include <boot/vfs.h>
#include <boot/platform.h>
@ -22,6 +25,7 @@
#include <boot/stdio.h>
#include <safemode.h>
#include <util/ring_buffer.h>
#include <util/SinglyLinkedList.h>
#include "kernel_debug_config.h"
@ -31,7 +35,7 @@
#include "RootFileSystem.h"
#define TRACE_MENU
//#define TRACE_MENU
#ifdef TRACE_MENU
# define TRACE(x) dprintf x
#else
@ -39,7 +43,11 @@
#endif
static char sSafeModeOptionsBuffer[2048];
// only set while in user_menu()
static Menu* sMainMenu = NULL;
static Menu* sBlacklistRootMenu = NULL;
static BootVolume* sBootVolume = NULL;
static PathBlacklist* sPathBlacklist;
MenuItem::MenuItem(const char *label, Menu *subMenu)
@ -489,22 +497,340 @@ size_to_string(off_t size, char* buffer, size_t bufferSize)
}
// #pragma mark - blacklist menu
class BlacklistMenuItem : public MenuItem {
public:
BlacklistMenuItem(char* label, Node* node, Menu* subMenu)
:
MenuItem(label, subMenu),
fNode(node),
fSubMenu(subMenu)
{
fNode->Acquire();
SetType(MENU_ITEM_MARKABLE);
}
~BlacklistMenuItem()
{
fNode->Release();
// make sure the submenu is destroyed
SetSubmenu(fSubMenu);
}
bool IsDirectoryItem() const
{
return fNode->Type() == S_IFDIR;
}
bool GetPath(BlacklistedPath& _path) const
{
Menu* menu = Supermenu();
if (menu != NULL && menu != sBlacklistRootMenu
&& menu->Superitem() != NULL) {
return static_cast<BlacklistMenuItem*>(menu->Superitem())
->GetPath(_path)
&& _path.Append(Label());
}
return _path.SetTo(Label());
}
void UpdateBlacklisted()
{
BlacklistedPath path;
if (GetPath(path))
_SetMarked(sPathBlacklist->Contains(path.Path()), false);
}
virtual void SetMarked(bool marked)
{
_SetMarked(marked, true);
}
static bool Less(const MenuItem* a, const MenuItem* b)
{
const BlacklistMenuItem* item1
= static_cast<const BlacklistMenuItem*>(a);
const BlacklistMenuItem* item2
= static_cast<const BlacklistMenuItem*>(b);
// directories come first
if (item1->IsDirectoryItem() != item2->IsDirectoryItem())
return item1->IsDirectoryItem();
// compare the labels
return strcasecmp(item1->Label(), item2->Label()) < 0;
}
private:
void _SetMarked(bool marked, bool updateBlacklist)
{
if (marked == IsMarked())
return;
// For directories toggle the availability of the submenu.
if (IsDirectoryItem())
SetSubmenu(marked ? NULL : fSubMenu);
if (updateBlacklist) {
BlacklistedPath path;
if (GetPath(path)) {
if (marked)
sPathBlacklist->Add(path.Path());
else
sPathBlacklist->Remove(path.Path());
}
}
MenuItem::SetMarked(marked);
}
private:
Node* fNode;
Menu* fSubMenu;
};
class BlacklistMenu : public Menu {
public:
BlacklistMenu()
:
Menu(STANDARD_MENU, "Mark the entries to blacklist"),
fDirectory(NULL)
{
}
~BlacklistMenu()
{
SetDirectory(NULL);
}
virtual void Entered()
{
_DeleteItems();
if (fDirectory == NULL)
return;
void* cookie;
if (fDirectory->Open(&cookie, O_RDONLY) == B_OK) {
Node* node;
while (fDirectory->GetNextNode(cookie, &node) == B_OK) {
BlacklistMenuItem* item = _CreateItem(node);
node->Release();
if (item == NULL)
break;
AddItem(item);
item->UpdateBlacklisted();
}
fDirectory->Close(cookie);
}
SortItems(&BlacklistMenuItem::Less);
}
virtual void Exited()
{
_DeleteItems();
}
protected:
void SetDirectory(Directory* directory)
{
if (fDirectory != NULL)
fDirectory->Release();
fDirectory = directory;
if (fDirectory != NULL)
fDirectory->Acquire();
}
private:
static BlacklistMenuItem* _CreateItem(Node* node)
{
// Get the node name and duplicate it, so we can use it as a label.
char name[B_FILE_NAME_LENGTH];
if (node->GetName(name, sizeof(name)) != B_OK)
return NULL;
// append '/' to directory labels
bool isDirectory = node->Type() == S_IFDIR;
if (isDirectory)
strlcat(name, "/", sizeof(name));
// If this is a directory, create the submenu.
BlacklistMenu* subMenu = NULL;
if (isDirectory) {
subMenu = new(std::nothrow) BlacklistMenu;
if (subMenu != NULL)
subMenu->SetDirectory(static_cast<Directory*>(node));
}
ObjectDeleter<BlacklistMenu> subMenuDeleter(subMenu);
// create the menu item
BlacklistMenuItem* item = new(std::nothrow) BlacklistMenuItem(name,
node, subMenu);
if (item == NULL)
return NULL;
subMenuDeleter.Detach();
return item;
}
void _DeleteItems()
{
int32 count = CountItems();
for (int32 i = 0; i < count; i++)
delete RemoveItemAt(0);
}
private:
Directory* fDirectory;
};
class BlacklistRootMenu : public BlacklistMenu {
public:
BlacklistRootMenu()
:
BlacklistMenu()
{
}
virtual void Entered()
{
// Get the system directory, but only if this is a packaged Haiku.
// Otherwise blacklisting isn't supported.
if (sBootVolume != NULL && sBootVolume->IsValid()
&& sBootVolume->IsPackaged()) {
SetDirectory(sBootVolume->SystemDirectory());
} else
SetDirectory(NULL);
BlacklistMenu::Entered();
}
virtual void Exited()
{
BlacklistMenu::Exited();
SetDirectory(NULL);
}
};
// #pragma mark -
class StringBuffer {
public:
StringBuffer()
:
fBuffer(NULL),
fLength(0),
fCapacity(0)
{
}
~StringBuffer()
{
free(fBuffer);
}
const char* String() const
{
return fBuffer != NULL ? fBuffer : "";
}
size_t Length() const
{
return fLength;
}
bool Append(const char* toAppend)
{
return Append(toAppend, strlen(toAppend));
}
bool Append(const char* toAppend, size_t length)
{
size_t oldLength = fLength;
if (!_Resize(fLength + length))
return false;
memcpy(fBuffer + oldLength, toAppend, length);
return true;
}
private:
bool _Resize(size_t newLength)
{
if (newLength >= fCapacity) {
size_t newCapacity = std::max(fCapacity, size_t(32));
while (newLength >= newCapacity)
newCapacity *= 2;
char* buffer = (char*)realloc(fBuffer, newCapacity);
if (buffer == NULL)
return false;
fBuffer = buffer;
fCapacity = newCapacity;
}
fBuffer[newLength] = '\0';
fLength = newLength;
return true;
}
private:
char* fBuffer;
size_t fLength;
size_t fCapacity;
};
// #pragma mark -
static StringBuffer sSafeModeOptionsBuffer;
static MenuItem*
get_continue_booting_menu_item()
{
// It's the last item in the main menu.
if (sMainMenu == NULL || sMainMenu->CountItems() == 0)
return NULL;
return sMainMenu->ItemAt(sMainMenu->CountItems() - 1);
}
static bool
user_menu_boot_volume(Menu* menu, MenuItem* item)
{
Menu* super = menu->Supermenu();
if (super == NULL) {
MenuItem* bootItem = get_continue_booting_menu_item();
if (bootItem == NULL) {
// huh?
return true;
}
MenuItem *bootItem = super->ItemAt(super->CountItems() - 1);
bootItem->SetEnabled(true);
bootItem->Select(true);
bootItem->SetData(item->Data());
if (sBootVolume->IsValid() && sBootVolume->RootDirectory() == item->Data())
return true;
sPathBlacklist->MakeEmpty();
bool valid = sBootVolume->SetTo((Directory*)item->Data()) == B_OK;
bootItem->SetEnabled(valid);
if (valid)
bootItem->Select(true);
gBootVolume.SetBool(BOOT_VOLUME_USER_SELECTED, true);
return true;
@ -653,10 +979,10 @@ debug_menu_add_advanced_option(Menu* menu, MenuItem* item)
if (size > 0) {
buffer[size] = '\n';
size_t pos = strlen(sSafeModeOptionsBuffer);
if (pos + size + 1 < sizeof(sSafeModeOptionsBuffer))
strlcat(sSafeModeOptionsBuffer, buffer,
sizeof(sSafeModeOptionsBuffer));
if (!sSafeModeOptionsBuffer.Append(buffer)) {
dprintf("debug_menu_add_advanced_option(): failed to append option "
"to buffer\n");
}
}
return true;
@ -699,7 +1025,7 @@ add_boot_volume_menu(Directory* bootVolume)
Directory* volume;
while (gRoot->GetNextNode(cookie, (Node**)&volume) == B_OK) {
// only list bootable volumes
if (!is_bootable(volume))
if (volume != bootVolume && !is_bootable(volume))
continue;
char name[B_FILE_NAME_LENGTH];
@ -793,6 +1119,13 @@ add_safe_mode_menu()
platform_add_menus(safeMenu);
safeMenu->AddSeparatorItem();
sBlacklistRootMenu = new(std::nothrow) BlacklistRootMenu;
safeMenu->AddItem(item = new(std::nothrow) MenuItem("Blacklist entries",
sBlacklistRootMenu));
item->SetHelpText("Allows to select system files that shall be ignored. "
"Useful e.g. to disable drivers temporarily.");
safeMenu->AddSeparatorItem();
safeMenu->AddItem(item = new(nothrow) MenuItem("Return to main menu"));
@ -962,18 +1295,43 @@ add_debug_menu()
static void
apply_safe_mode_options(Menu* menu)
{
int32 pos = strlen(sSafeModeOptionsBuffer);
size_t bufferSize = sizeof(sSafeModeOptionsBuffer);
MenuItemIterator iterator = menu->ItemIterator();
while (MenuItem* item = iterator.Next()) {
if (item->Type() == MENU_ITEM_SEPARATOR || !item->IsMarked()
|| item->Data() == NULL || (uint32)pos >= bufferSize)
|| item->Data() == NULL) {
continue;
}
size_t totalBytes = snprintf(sSafeModeOptionsBuffer + pos,
bufferSize - pos, "%s true\n", (const char*)item->Data());
pos += std::min(totalBytes, bufferSize - pos - 1);
char buffer[256];
if (snprintf(buffer, sizeof(buffer), "%s true\n",
(const char*)item->Data()) >= (int)sizeof(buffer)
|| !sSafeModeOptionsBuffer.Append(buffer)) {
dprintf("apply_safe_mode_options(): failed to append option to "
"buffer\n");
}
}
}
static void
apply_safe_mode_path_blacklist()
{
if (sPathBlacklist->IsEmpty())
return;
bool success = sSafeModeOptionsBuffer.Append("EntryBlacklist {\n");
for (PathBlacklist::Iterator it = sPathBlacklist->GetIterator();
BlacklistedPath* path = it.Next();) {
success &= sSafeModeOptionsBuffer.Append(path->Path());
success &= sSafeModeOptionsBuffer.Append("\n", 1);
}
success &= sSafeModeOptionsBuffer.Append("}\n");
if (!success) {
dprintf("apply_safe_mode_options(): failed to append path "
"blacklist to buffer\n");
}
}
@ -987,17 +1345,21 @@ user_menu_reboot(Menu* menu, MenuItem* item)
status_t
user_menu(BootVolume& _bootVolume)
user_menu(BootVolume& _bootVolume, PathBlacklist& _pathBlacklist)
{
Menu* menu = new(std::nothrow) Menu(MAIN_MENU);
sMainMenu = menu;
sBootVolume = &_bootVolume;
sPathBlacklist = &_pathBlacklist;
Menu* safeModeMenu = NULL;
Menu* debugMenu = NULL;
MenuItem* item;
TRACE(("user_menu: enter\n"));
memset(sSafeModeOptionsBuffer, 0, sizeof(sSafeModeOptionsBuffer));
// Add boot volume
menu->AddItem(item = new(std::nothrow) MenuItem("Select boot volume",
add_boot_volume_menu(_bootVolume.RootDirectory())));
@ -1028,18 +1390,18 @@ user_menu(BootVolume& _bootVolume)
menu->Run();
// See if a new boot device has been selected, and propagate that back
if (item->Data() != NULL)
_bootVolume.SetTo((Directory*)item->Data());
apply_safe_mode_options(safeModeMenu);
apply_safe_mode_options(debugMenu);
add_safe_mode_settings(sSafeModeOptionsBuffer);
apply_safe_mode_path_blacklist();
add_safe_mode_settings(sSafeModeOptionsBuffer.String());
delete menu;
TRACE(("user_menu: leave\n"));
sMainMenu = NULL;
sBlacklistRootMenu = NULL;
sBootVolume = NULL;
sPathBlacklist = NULL;
return B_OK;
}

View File

@ -9,7 +9,11 @@
#include <boot/vfs.h>
extern status_t user_menu(BootVolume& _bootVolume);
class PathBlacklist;
extern status_t user_menu(BootVolume& _bootVolume,
PathBlacklist& _pathBlacklist);
#endif /* MENU_H */