mount_server: Use scoring mechanism to detect volume
* This makes mounting volumes more stable; ie. you can put your drive in another slot, or boot your native system in emulation, and it will still find the drives to mount. * The old method is still left there in order to achieve a smooth transition.
This commit is contained in:
parent
ad33fd78a5
commit
ae47dec0fd
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2007-2010, Haiku, Inc. All rights reserved.
|
||||
* Copyright 2007-2018, Haiku, Inc. All rights reserved.
|
||||
* Distributed under the terms of the MIT License.
|
||||
*
|
||||
* Authors:
|
||||
@ -40,6 +40,8 @@
|
||||
|
||||
#include "MountServer.h"
|
||||
|
||||
#include "Utilities.h"
|
||||
|
||||
|
||||
#undef B_TRANSLATION_CONTEXT
|
||||
#define B_TRANSLATION_CONTEXT "AutoMounter"
|
||||
@ -51,11 +53,296 @@ static const char* kMountFlagsKeyExtension = " mount flags";
|
||||
static const char* kInitialMountEvent = "initial_volumes_mounted";
|
||||
|
||||
|
||||
class MountVisitor : public BDiskDeviceVisitor {
|
||||
public:
|
||||
MountVisitor(mount_mode normalMode,
|
||||
mount_mode removableMode,
|
||||
bool initialRescan, BMessage& previous,
|
||||
partition_id deviceID);
|
||||
virtual ~MountVisitor()
|
||||
{}
|
||||
|
||||
virtual bool Visit(BDiskDevice* device);
|
||||
virtual bool Visit(BPartition* partition, int32 level);
|
||||
|
||||
private:
|
||||
bool _WasPreviouslyMounted(const BPath& path,
|
||||
const BPartition* partition);
|
||||
|
||||
private:
|
||||
mount_mode fNormalMode;
|
||||
mount_mode fRemovableMode;
|
||||
bool fInitialRescan;
|
||||
BMessage& fPrevious;
|
||||
partition_id fOnlyOnDeviceID;
|
||||
};
|
||||
|
||||
|
||||
class MountArchivedVisitor : public BDiskDeviceVisitor {
|
||||
public:
|
||||
MountArchivedVisitor(
|
||||
const BDiskDeviceList& devices,
|
||||
const BMessage& archived);
|
||||
virtual ~MountArchivedVisitor();
|
||||
|
||||
virtual bool Visit(BDiskDevice* device);
|
||||
virtual bool Visit(BPartition* partition, int32 level);
|
||||
|
||||
private:
|
||||
int _Score(BPartition* partition);
|
||||
|
||||
private:
|
||||
const BDiskDeviceList& fDevices;
|
||||
const BMessage& fArchived;
|
||||
int fBestScore;
|
||||
partition_id fBestID;
|
||||
};
|
||||
|
||||
|
||||
static bool
|
||||
BootedInSafeMode()
|
||||
{
|
||||
const char *safeMode = getenv("SAFEMODE");
|
||||
return (safeMode && strcmp(safeMode, "yes") == 0);
|
||||
const char* safeMode = getenv("SAFEMODE");
|
||||
return safeMode != NULL && strcmp(safeMode, "yes") == 0;
|
||||
}
|
||||
|
||||
|
||||
class ArchiveVisitor : public BDiskDeviceVisitor {
|
||||
public:
|
||||
ArchiveVisitor(BMessage& message);
|
||||
virtual ~ArchiveVisitor();
|
||||
|
||||
virtual bool Visit(BDiskDevice* device);
|
||||
virtual bool Visit(BPartition* partition, int32 level);
|
||||
|
||||
private:
|
||||
BMessage& fMessage;
|
||||
};
|
||||
|
||||
|
||||
// #pragma mark - MountVisitor
|
||||
|
||||
|
||||
MountVisitor::MountVisitor(mount_mode normalMode, mount_mode removableMode,
|
||||
bool initialRescan, BMessage& previous, partition_id deviceID)
|
||||
:
|
||||
fNormalMode(normalMode),
|
||||
fRemovableMode(removableMode),
|
||||
fInitialRescan(initialRescan),
|
||||
fPrevious(previous),
|
||||
fOnlyOnDeviceID(deviceID)
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
bool
|
||||
MountVisitor::Visit(BDiskDevice* device)
|
||||
{
|
||||
return Visit(device, 0);
|
||||
}
|
||||
|
||||
|
||||
bool
|
||||
MountVisitor::Visit(BPartition* partition, int32 level)
|
||||
{
|
||||
if (fOnlyOnDeviceID >= 0) {
|
||||
// only mount partitions on the given device id
|
||||
// or if the partition ID is already matched
|
||||
BPartition* device = partition;
|
||||
while (device->Parent() != NULL) {
|
||||
if (device->ID() == fOnlyOnDeviceID) {
|
||||
// we are happy
|
||||
break;
|
||||
}
|
||||
device = device->Parent();
|
||||
}
|
||||
if (device->ID() != fOnlyOnDeviceID)
|
||||
return false;
|
||||
}
|
||||
|
||||
mount_mode mode = !fInitialRescan && partition->Device()->IsRemovableMedia()
|
||||
? fRemovableMode : fNormalMode;
|
||||
if (mode == kNoVolumes || partition->IsMounted()
|
||||
|| !partition->ContainsFileSystem()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
BPath path;
|
||||
if (partition->GetPath(&path) != B_OK)
|
||||
return false;
|
||||
|
||||
if (mode == kRestorePreviousVolumes) {
|
||||
// mount all volumes that were stored in the settings file
|
||||
if (!_WasPreviouslyMounted(path, partition))
|
||||
return false;
|
||||
} else if (mode == kOnlyBFSVolumes) {
|
||||
if (partition->ContentType() == NULL
|
||||
|| strcmp(partition->ContentType(), kPartitionTypeBFS))
|
||||
return false;
|
||||
}
|
||||
|
||||
uint32 mountFlags;
|
||||
if (!fInitialRescan) {
|
||||
// Ask the user about mount flags if this is not the
|
||||
// initial scan.
|
||||
// TODO!
|
||||
//if (!_SuggestMountFlags(partition, &mountFlags))
|
||||
return false;
|
||||
} else {
|
||||
BString mountFlagsKey(path.Path());
|
||||
mountFlagsKey << kMountFlagsKeyExtension;
|
||||
if (fPrevious.FindInt32(mountFlagsKey.String(),
|
||||
(int32*)&mountFlags) < B_OK) {
|
||||
mountFlags = 0;
|
||||
}
|
||||
}
|
||||
|
||||
if (partition->Mount(NULL, mountFlags) != B_OK) {
|
||||
// TODO: Error to syslog
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
bool
|
||||
MountVisitor::_WasPreviouslyMounted(const BPath& path,
|
||||
const BPartition* partition)
|
||||
{
|
||||
// We only check the legacy config data here; the current method
|
||||
// is implemented in ArchivedVolumeVisitor -- this can be removed
|
||||
// some day.
|
||||
const char* volumeName = NULL;
|
||||
if (partition->ContentName() == NULL
|
||||
|| fPrevious.FindString(path.Path(), &volumeName) != B_OK
|
||||
|| strcmp(volumeName, partition->ContentName()) != 0)
|
||||
return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
// #pragma mark - MountArchivedVisitor
|
||||
|
||||
|
||||
MountArchivedVisitor::MountArchivedVisitor(const BDiskDeviceList& devices,
|
||||
const BMessage& archived)
|
||||
:
|
||||
fDevices(devices),
|
||||
fArchived(archived),
|
||||
fBestScore(-1),
|
||||
fBestID(-1)
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
MountArchivedVisitor::~MountArchivedVisitor()
|
||||
{
|
||||
if (fBestScore >= 6) {
|
||||
uint32 mountFlags = fArchived.GetUInt32("mountFlags", 0);
|
||||
BPartition* partition = fDevices.PartitionWithID(fBestID);
|
||||
if (partition != NULL)
|
||||
partition->Mount(NULL, mountFlags);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
bool
|
||||
MountArchivedVisitor::Visit(BDiskDevice* device)
|
||||
{
|
||||
return Visit(device, 0);
|
||||
}
|
||||
|
||||
|
||||
bool
|
||||
MountArchivedVisitor::Visit(BPartition* partition, int32 level)
|
||||
{
|
||||
if (partition->IsMounted() || !partition->ContainsFileSystem())
|
||||
return false;
|
||||
|
||||
int score = _Score(partition);
|
||||
if (score > fBestScore) {
|
||||
fBestScore = score;
|
||||
fBestID = partition->ID();
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
int
|
||||
MountArchivedVisitor::_Score(BPartition* partition)
|
||||
{
|
||||
BPath path;
|
||||
if (partition->GetPath(&path) != B_OK)
|
||||
return false;
|
||||
|
||||
int score = 0;
|
||||
|
||||
int64 capacity = fArchived.GetInt64("capacity", 0);
|
||||
if (capacity == partition->ContentSize())
|
||||
score += 4;
|
||||
|
||||
BString deviceName = fArchived.GetString("deviceName");
|
||||
if (deviceName == path.Path())
|
||||
score += 3;
|
||||
|
||||
BString volumeName = fArchived.GetString("volumeName");
|
||||
if (volumeName == partition->ContentName())
|
||||
score += 2;
|
||||
|
||||
BString fsName = fArchived.FindString("fsName");
|
||||
if (fsName == partition->ContentType())
|
||||
score += 1;
|
||||
|
||||
uint32 blockSize = fArchived.GetUInt32("blockSize", 0);
|
||||
if (blockSize == partition->BlockSize())
|
||||
score += 1;
|
||||
|
||||
return score;
|
||||
}
|
||||
|
||||
|
||||
// #pragma mark - ArchiveVisitor
|
||||
|
||||
|
||||
ArchiveVisitor::ArchiveVisitor(BMessage& message)
|
||||
:
|
||||
fMessage(message)
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
ArchiveVisitor::~ArchiveVisitor()
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
bool
|
||||
ArchiveVisitor::Visit(BDiskDevice* device)
|
||||
{
|
||||
return Visit(device, 0);
|
||||
}
|
||||
|
||||
|
||||
bool
|
||||
ArchiveVisitor::Visit(BPartition* partition, int32 level)
|
||||
{
|
||||
if (!partition->ContainsFileSystem())
|
||||
return false;
|
||||
|
||||
BPath path;
|
||||
if (partition->GetPath(&path) != B_OK)
|
||||
return false;
|
||||
|
||||
BMessage info;
|
||||
info.AddUInt32("blockSize", partition->BlockSize());
|
||||
info.AddInt64("capacity", partition->ContentSize());
|
||||
info.AddString("deviceName", path.Path());
|
||||
info.AddString("volumeName", partition->ContentName());
|
||||
info.AddString("fsName", partition->ContentType());
|
||||
|
||||
fMessage.AddMessage("info", &info);
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
@ -273,108 +560,23 @@ AutoMounter::_MountVolumes(mount_mode normal, mount_mode removable,
|
||||
if (normal == kNoVolumes && removable == kNoVolumes)
|
||||
return;
|
||||
|
||||
class InitialMountVisitor : public BDiskDeviceVisitor {
|
||||
public:
|
||||
InitialMountVisitor(mount_mode normalMode, mount_mode removableMode,
|
||||
bool initialRescan, BMessage& previous,
|
||||
partition_id deviceID)
|
||||
:
|
||||
fNormalMode(normalMode),
|
||||
fRemovableMode(removableMode),
|
||||
fInitialRescan(initialRescan),
|
||||
fPrevious(previous),
|
||||
fOnlyOnDeviceID(deviceID)
|
||||
{
|
||||
}
|
||||
|
||||
virtual
|
||||
~InitialMountVisitor()
|
||||
{
|
||||
}
|
||||
|
||||
virtual bool
|
||||
Visit(BDiskDevice* device)
|
||||
{
|
||||
return Visit(device, 0);
|
||||
}
|
||||
|
||||
virtual bool
|
||||
Visit(BPartition* partition, int32 level)
|
||||
{
|
||||
if (fOnlyOnDeviceID >= 0) {
|
||||
// only mount partitions on the given device id
|
||||
// or if the partition ID is already matched
|
||||
BPartition* device = partition;
|
||||
while (device->Parent() != NULL) {
|
||||
if (device->ID() == fOnlyOnDeviceID) {
|
||||
// we are happy
|
||||
break;
|
||||
}
|
||||
device = device->Parent();
|
||||
}
|
||||
if (device->ID() != fOnlyOnDeviceID)
|
||||
return false;
|
||||
}
|
||||
|
||||
mount_mode mode = !fInitialRescan
|
||||
&& partition->Device()->IsRemovableMedia()
|
||||
? fRemovableMode : fNormalMode;
|
||||
if (mode == kNoVolumes
|
||||
|| partition->IsMounted()
|
||||
|| !partition->ContainsFileSystem())
|
||||
return false;
|
||||
|
||||
BPath path;
|
||||
if (partition->GetPath(&path) != B_OK)
|
||||
return false;
|
||||
|
||||
if (mode == kRestorePreviousVolumes) {
|
||||
// mount all volumes that were stored in the settings file
|
||||
const char *volumeName = NULL;
|
||||
if (partition->ContentName() == NULL
|
||||
|| fPrevious.FindString(path.Path(), &volumeName)
|
||||
!= B_OK
|
||||
|| strcmp(volumeName, partition->ContentName()))
|
||||
return false;
|
||||
} else if (mode == kOnlyBFSVolumes) {
|
||||
if (partition->ContentType() == NULL
|
||||
|| strcmp(partition->ContentType(), kPartitionTypeBFS))
|
||||
return false;
|
||||
}
|
||||
|
||||
uint32 mountFlags;
|
||||
if (!fInitialRescan) {
|
||||
// Ask the user about mount flags if this is not the
|
||||
// initial scan.
|
||||
if (!_SuggestMountFlags(partition, &mountFlags))
|
||||
return false;
|
||||
} else {
|
||||
BString mountFlagsKey(path.Path());
|
||||
mountFlagsKey << kMountFlagsKeyExtension;
|
||||
if (fPrevious.FindInt32(mountFlagsKey.String(),
|
||||
(int32*)&mountFlags) < B_OK) {
|
||||
mountFlags = 0;
|
||||
}
|
||||
}
|
||||
|
||||
if (partition->Mount(NULL, mountFlags) != B_OK) {
|
||||
// TODO: Error to syslog
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
private:
|
||||
mount_mode fNormalMode;
|
||||
mount_mode fRemovableMode;
|
||||
bool fInitialRescan;
|
||||
BMessage& fPrevious;
|
||||
partition_id fOnlyOnDeviceID;
|
||||
} visitor(normal, removable, initialRescan, fSettings, deviceID);
|
||||
|
||||
BDiskDeviceList devices;
|
||||
status_t status = devices.Fetch();
|
||||
if (status == B_OK)
|
||||
devices.VisitEachPartition(&visitor);
|
||||
if (status != B_OK)
|
||||
return;
|
||||
|
||||
if (normal == kRestorePreviousVolumes) {
|
||||
BMessage archived;
|
||||
for (int32 index = 0;
|
||||
fSettings.FindMessage("info", index, &archived) == B_OK;
|
||||
index++) {
|
||||
MountArchivedVisitor visitor(devices, archived);
|
||||
devices.VisitEachPartition(&visitor);
|
||||
}
|
||||
}
|
||||
|
||||
MountVisitor visitor(normal, removable, initialRescan, fSettings, deviceID);
|
||||
devices.VisitEachPartition(&visitor);
|
||||
}
|
||||
|
||||
|
||||
@ -591,7 +793,7 @@ AutoMounter::_FromMode(mount_mode mode, bool& all, bool& bfs, bool& restore)
|
||||
}
|
||||
|
||||
|
||||
AutoMounter::mount_mode
|
||||
mount_mode
|
||||
AutoMounter::_ToMode(bool all, bool bfs, bool restore)
|
||||
{
|
||||
if (all)
|
||||
@ -673,7 +875,7 @@ AutoMounter::_WriteSettings()
|
||||
|
||||
ssize_t settingsSize = message.FlattenedSize();
|
||||
|
||||
char *buffer = new(std::nothrow) char[settingsSize];
|
||||
char* buffer = new(std::nothrow) char[settingsSize];
|
||||
if (buffer == NULL) {
|
||||
PRINT(("error writing automounter settings, out of memory\n"));
|
||||
return;
|
||||
@ -682,6 +884,8 @@ AutoMounter::_WriteSettings()
|
||||
status_t result = message.Flatten(buffer, settingsSize);
|
||||
|
||||
fPrefsFile.Seek(0, SEEK_SET);
|
||||
fPrefsFile.SetSize(0);
|
||||
|
||||
result = fPrefsFile.Write(buffer, (size_t)settingsSize);
|
||||
if (result != settingsSize)
|
||||
PRINT(("error writing automounter settings, %s\n", strerror(result)));
|
||||
@ -741,22 +945,8 @@ AutoMounter::_GetSettings(BMessage *message)
|
||||
|
||||
// Save mounted volumes so we can optionally mount them on next
|
||||
// startup
|
||||
BVolumeRoster volumeRoster;
|
||||
BVolume volume;
|
||||
while (volumeRoster.GetNextVolume(&volume) == B_OK) {
|
||||
fs_info info;
|
||||
if (fs_stat_dev(volume.Device(), &info) == 0
|
||||
&& (info.flags & (B_FS_IS_REMOVABLE | B_FS_IS_PERSISTENT)) != 0) {
|
||||
message->AddString(info.device_name, info.volume_name);
|
||||
|
||||
BString mountFlagsKey(info.device_name);
|
||||
mountFlagsKey << kMountFlagsKeyExtension;
|
||||
uint32 mountFlags = 0;
|
||||
if (volume.IsReadOnly())
|
||||
mountFlags |= B_MOUNT_READ_ONLY;
|
||||
message->AddInt32(mountFlagsKey.String(), mountFlags);
|
||||
}
|
||||
}
|
||||
ArchiveVisitor visitor(*message);
|
||||
BDiskDeviceRoster().VisitEachMountedPartition(&visitor);
|
||||
}
|
||||
|
||||
|
||||
|
@ -16,6 +16,14 @@ class BPartition;
|
||||
class BPath;
|
||||
|
||||
|
||||
enum mount_mode {
|
||||
kNoVolumes,
|
||||
kOnlyBFSVolumes,
|
||||
kAllVolumes,
|
||||
kRestorePreviousVolumes
|
||||
};
|
||||
|
||||
|
||||
class AutoMounter : public BServer {
|
||||
public:
|
||||
AutoMounter();
|
||||
@ -26,13 +34,6 @@ public:
|
||||
virtual bool QuitRequested();
|
||||
|
||||
private:
|
||||
enum mount_mode {
|
||||
kNoVolumes,
|
||||
kOnlyBFSVolumes,
|
||||
kAllVolumes,
|
||||
kRestorePreviousVolumes
|
||||
};
|
||||
|
||||
void _GetSettings(BMessage* message);
|
||||
|
||||
void _MountVolumes(mount_mode normal,
|
||||
|
@ -1,12 +1,13 @@
|
||||
SubDir HAIKU_TOP src servers mount ;
|
||||
|
||||
UsePrivateHeaders app mount shared storage ;
|
||||
SubDirHdrs $(HAIKU_TOP) src kits tracker ;
|
||||
|
||||
Server mount_server
|
||||
:
|
||||
AutoMounter.cpp
|
||||
:
|
||||
libbe.so localestub [ TargetLibstdc++ ]
|
||||
libbe.so tracker localestub [ TargetLibstdc++ ]
|
||||
:
|
||||
mount_server.rdef
|
||||
;
|
||||
|
Loading…
Reference in New Issue
Block a user