Work in progress of moving the (audo-)mounting functionality from Tracker into

a dedicated mount server. This is pretty much a straight copy from the
AutoMounter code from Tracker, except
* the eject on unmount setting has been added (in Tracker, it's part of the
  general settings, not the mount specific ones),
* scripting features have been added, such that it becomes possible to trigger
  mounting the previoulsy mounted volumes from the outside, and most
  importantly block until the operation is done (waiting for the reply).

TODO:
* Change Tracker to not run it's own AutoMounter, but send messages to the
  new server.
* Move the eject when unmounting setting to the mount settings window.
* Enable the mount_server in the Bootscript.


git-svn-id: file:///srv/svn/repos/haiku/haiku/trunk@33484 a95241bf-73f2-0310-859d-f6bbb57e9c96
This commit is contained in:
Stephan Aßmus 2009-10-07 18:34:29 +00:00
parent e10035a02e
commit 21f2402e20
7 changed files with 1128 additions and 3 deletions

View File

@ -0,0 +1,20 @@
/*
* Copyright 2007-2009, Haiku, Inc. All rights reserved.
* Distributed under the terms of the MIT License.
*/
#ifndef _MOUNT_SERVER_H
#define _MOUNT_SERVER_H
#include <SupportDefs.h>
const uint32 kMountVolume = 'mntv';
const uint32 kMountAllNow = 'mntn';
const uint32 kSetAutomounterParams = 'pmst';
const uint32 kVolumeMounted = 'vmtd';
const uint32 kUnmountVolume = 'umnt';
const char* kMountServerSignature = "application/x-vnd.Haiku-mount_server";
#endif // _MOUNT_SERVER_H

View File

@ -9,6 +9,7 @@ SubInclude HAIKU_TOP src servers mail ;
SubInclude HAIKU_TOP src servers media ;
SubInclude HAIKU_TOP src servers media_addon ;
SubInclude HAIKU_TOP src servers midi ;
SubInclude HAIKU_TOP src servers mount ;
SubInclude HAIKU_TOP src servers net ;
SubInclude HAIKU_TOP src servers power ;
SubInclude HAIKU_TOP src servers print ;

View File

@ -34,6 +34,16 @@ typedef PixelFormat::agg_buffer agg_buffer;
d[2] = (((((r) - _p.data8[2]) * (a)) + (_p.data8[2] << 8)) >> 8); \
d[3] = 255; \
}
//#define BLEND(d, r, g, b, a) \
//{ \
// pixel32 _p; \
// _p.data32 = *(uint32*)d; \
// d[0] = (((((b) - _p.data8[0]) * (a)) + ((_p.data8[0] << 8) | _p.data8[0])) / 255); \
// d[1] = (((((g) - _p.data8[1]) * (a)) + ((_p.data8[1] << 8) | _p.data8[1])) / 255); \
// d[2] = (((((r) - _p.data8[2]) * (a)) + ((_p.data8[2] << 8) | _p.data8[2])) / 255); \
// d[3] = 255; \
//}
#define BLEND_SUBPIX(d, r, g, b, a1, a2, a3) \
{ \
@ -44,6 +54,15 @@ typedef PixelFormat::agg_buffer agg_buffer;
d[2] = (((((r) - _p.data8[2]) * (a3)) + (_p.data8[2] << 8)) >> 8); \
d[3] = 255; \
}
//#define BLEND_SUBPIX(d, r, g, b, a1, a2, a3) \
//{ \
// pixel32 _p; \
// _p.data32 = *(uint32*)d; \
// d[0] = (((((b) - _p.data8[0]) * (a1)) + ((_p.data8[0] << 8) | _p.data8[0])) / 255); \
// d[1] = (((((g) - _p.data8[1]) * (a2)) + ((_p.data8[1] << 8) | _p.data8[1])) / 255); \
// d[2] = (((((r) - _p.data8[2]) * (a3)) + ((_p.data8[2] << 8) | _p.data8[2])) / 255); \
// d[3] = 255; \
//}
// BLEND_FROM
//
@ -59,6 +78,13 @@ typedef PixelFormat::agg_buffer agg_buffer;
d[2] = (((((r2) - (r1)) * (a)) + ((r1) << 8)) >> 8); \
d[3] = 255; \
}
//#define BLEND_FROM(d, r1, g1, b1, r2, g2, b2, a) \
//{ \
// d[0] = (((((b2) - (b1)) * (a)) + ((b1) << 8) | b1) / 255); \
// d[1] = (((((g2) - (g1)) * (a)) + ((g1) << 8) | g1) / 255); \
// d[2] = (((((r2) - (r1)) * (a)) + ((r1) << 8) | r1) / 255); \
// d[3] = 255; \
//}
#define BLEND_FROM_SUBPIX(d, r1, g1, b1, r2, g2, b2, a1, a2, a3) \
{ \
@ -67,6 +93,13 @@ typedef PixelFormat::agg_buffer agg_buffer;
d[2] = (((((r2) - (r1)) * (a3)) + ((r1) << 8)) >> 8); \
d[3] = 255; \
}
//#define BLEND_FROM_SUBPIX(d, r1, g1, b1, r2, g2, b2, a1, a2, a3) \
//{ \
// d[0] = (((((b2) - (b1)) * (a1)) + ((b1) << 8) | b1) / 255); \
// d[1] = (((((g2) - (g1)) * (a2)) + ((g1) << 8) | g1) / 255); \
// d[2] = (((((r2) - (r1)) * (a3)) + ((r1) << 8) | r1) / 255); \
// d[3] = 255; \
//}
// BLEND16
//
@ -83,15 +116,33 @@ typedef PixelFormat::agg_buffer agg_buffer;
d[2] = (((((r) - _p.data8[2]) * (a)) + (_p.data8[2] << 16)) >> 16); \
d[3] = 255; \
}
//#define BLEND16(d, r, g, b, a) \
//{ \
// pixel32 _p; \
// _p.data32 = *(uint32*)d; \
// d[0] = (((((b) - _p.data8[0]) * (a)) + (_p.data8[0] << 16)) / 65025); \
// d[1] = (((((g) - _p.data8[1]) * (a)) + (_p.data8[1] << 16)) / 65025); \
// d[2] = (((((r) - _p.data8[2]) * (a)) + (_p.data8[2] << 16)) / 65025); \
// d[3] = 255; \
//}
// BLEND16_SUBPIX
//#define BLEND16_SUBPIX(d, r, g, b, a1, a2, a3) \
//{ \
// pixel32 _p; \
// _p.data32 = *(uint32*)d; \
// d[0] = (((((b) - _p.data8[0]) * (a1)) + (_p.data8[0] << 16)) >> 16); \
// d[1] = (((((g) - _p.data8[1]) * (a2)) + (_p.data8[1] << 16)) >> 16); \
// d[2] = (((((r) - _p.data8[2]) * (a3)) + (_p.data8[2] << 16)) >> 16); \
// d[3] = 255; \
//}
#define BLEND16_SUBPIX(d, r, g, b, a1, a2, a3) \
{ \
pixel32 _p; \
_p.data32 = *(uint32*)d; \
d[0] = (((((b) - _p.data8[0]) * (a1)) + (_p.data8[0] << 16)) >> 16); \
d[1] = (((((g) - _p.data8[1]) * (a2)) + (_p.data8[1] << 16)) >> 16); \
d[2] = (((((r) - _p.data8[2]) * (a3)) + (_p.data8[2] << 16)) >> 16); \
d[0] = (((((b) - _p.data8[0]) * (a1)) + (_p.data8[0] * 65025)) / 65025); \
d[1] = (((((g) - _p.data8[1]) * (a2)) + (_p.data8[1] * 65025)) / 65025); \
d[2] = (((((r) - _p.data8[2]) * (a3)) + (_p.data8[2] * 65025)) / 65025); \
d[3] = 255; \
}

View File

@ -0,0 +1,908 @@
/*
* Copyright 2007-2009, Haiku, Inc. All rights reserved.
* Distributed under the terms of the MIT License.
*/
#include "AutoMounter.h"
#include <new>
#include <string.h>
#include <unistd.h>
#include <Alert.h>
#include <AutoLocker.h>
#include <Debug.h>
#include <Directory.h>
#include <DiskDevice.h>
#include <DiskDeviceRoster.h>
#include <DiskDeviceList.h>
#include <DiskDeviceTypes.h>
#include <DiskSystem.h>
#include <FindDirectory.h>
#include <fs_info.h>
#include <fs_volume.h>
#include <Message.h>
#include <Node.h>
#include <NodeMonitor.h>
#include <Path.h>
#include <PropertyInfo.h>
#include <String.h>
#include <VolumeRoster.h>
//#include "AutoMounterSettings.h"
#include "MountServer.h"
static const char* kMountServerSettings = "mount_server";
static const uint32 kMsgInitialScan = 'insc';
static const char* kMountFlagsKeyExtension = " mount flags";
bool
BootedInSafeMode()
{
const char *safeMode = getenv("SAFEMODE");
return (safeMode && strcmp(safeMode, "yes") == 0);
}
// #pragma mark -
AutoMounter::AutoMounter()
:
BApplication(kMountServerSignature),
fNormalMode(kRestorePreviousVolumes),
fRemovableMode(kAllVolumes),
fEjectWhenUnmounting(true)
{
set_thread_priority(Thread(), B_LOW_PRIORITY);
if (!BootedInSafeMode()) {
_ReadSettings();
} else {
// defeat automounter in safe mode, don't even care about the settings
fNormalMode = kNoVolumes;
fRemovableMode = kNoVolumes;
}
BDiskDeviceRoster().StartWatching(this,
B_DEVICE_REQUEST_DEVICE | B_DEVICE_REQUEST_DEVICE_LIST);
}
AutoMounter::~AutoMounter()
{
BDiskDeviceRoster().StopWatching(this);
}
void
AutoMounter::MessageReceived(BMessage* message)
{
switch (message->what) {
case B_EXECUTE_PROPERTY:
{
int32 index;
BMessage specifier;
int32 what;
const char* property = NULL;
if (message->GetCurrentSpecifier(&index, &specifier, &what,
&property) < B_OK
|| !_ScriptReceived(message, index, &specifier, what,
property)) {
BApplication::MessageReceived(message);
}
break;
}
case kMsgInitialScan:
_MountVolumes(fNormalMode, fRemovableMode, true);
break;
case kMountVolume:
_MountVolume(message);
break;
case kUnmountVolume:
_UnmountAndEjectVolume(message);
break;
case kSetAutomounterParams:
{
bool rescanNow = false;
message->FindBool("rescanNow", &rescanNow);
_UpdateSettingsFromMessage(message);
_GetSettings(&fSettings);
_WriteSettings();
if (rescanNow)
_MountVolumes(fNormalMode, fRemovableMode);
break;
}
case kMountAllNow:
_MountVolumes(kAllVolumes, kAllVolumes);
break;
case B_DEVICE_UPDATE:
int32 event;
if (message->FindInt32("event", &event) != B_OK
|| (event != B_DEVICE_MEDIA_CHANGED
&& event != B_DEVICE_ADDED))
break;
partition_id deviceID;
if (message->FindInt32("id", &deviceID) != B_OK)
break;
_MountVolumes(kNoVolumes, fRemovableMode, false, deviceID);
break;
#if 0
case B_NODE_MONITOR:
{
int32 opcode;
if (message->FindInt32("opcode", &opcode) != B_OK)
break;
switch (opcode) {
// The name of a mount point has changed
case B_ENTRY_MOVED: {
WRITELOG(("*** Received Mount Point Renamed Notification"));
const char *newName;
if (message->FindString("name", &newName) != B_OK) {
WRITELOG(("ERROR: Couldn't find name field in update message"));
PRINT_OBJECT(*message);
break ;
}
//
// When the node monitor reports a move, it gives the
// parent device and inode that moved. The problem is
// that the inode is the inode of root *in* the filesystem,
// which is generally always the same number for every
// filesystem of a type.
//
// What we'd really like is the device that the moved
// volume is mounted on. Find this by using the
// *new* name and directory, and then stat()ing that to
// find the device.
//
dev_t parentDevice;
if (message->FindInt32("device", &parentDevice) != B_OK) {
WRITELOG(("ERROR: Couldn't find 'device' field in update"
" message"));
PRINT_OBJECT(*message);
break;
}
ino_t toDirectory;
if (message->FindInt64("to directory", &toDirectory)!=B_OK){
WRITELOG(("ERROR: Couldn't find 'to directory' field in update"
"message"));
PRINT_OBJECT(*message);
break;
}
entry_ref root_entry(parentDevice, toDirectory, newName);
BNode entryNode(&root_entry);
if (entryNode.InitCheck() != B_OK) {
WRITELOG(("ERROR: Couldn't create mount point entry node: %s/n",
strerror(entryNode.InitCheck())));
break;
}
node_ref mountPointNode;
if (entryNode.GetNodeRef(&mountPointNode) != B_OK) {
WRITELOG(("ERROR: Couldn't get node ref for new mount point"));
break;
}
WRITELOG(("Attempt to rename device %li to %s", mountPointNode.device,
newName));
Partition *partition = FindPartition(mountPointNode.device);
if (partition != NULL) {
WRITELOG(("Found device, changing name."));
BVolume mountVolume(partition->VolumeDeviceID());
BDirectory mountDir;
mountVolume.GetRootDirectory(&mountDir);
BPath dirPath(&mountDir, 0);
partition->SetMountedAt(dirPath.Path());
partition->SetVolumeName(newName);
break;
} else {
WRITELOG(("ERROR: Device %li does not appear to be present",
mountPointNode.device));
}
}
}
break;
}
#endif
default:
BLooper::MessageReceived(message);
break;
}
}
bool
AutoMounter::QuitRequested()
{
if (!BootedInSafeMode()) {
// don't write out settings in safe mode - this would overwrite the
// normal, non-safe mode settings
_WriteSettings();
}
return true;
}
// #pragma mark - scripting
const uint32 kApplication = 0;
static property_info sPropertyInfo[] = {
{
"InitialScan",
{B_EXECUTE_PROPERTY},
{B_DIRECT_SPECIFIER},
NULL, kApplication,
{B_STRING_TYPE},
{},
{}
},
{}
};
BHandler*
AutoMounter::ResolveSpecifier(BMessage* message, int32 index,
BMessage* specifier, int32 what, const char* property)
{
BPropertyInfo propInfo(sPropertyInfo);
uint32 data;
if (propInfo.FindMatch(message, 0, specifier, what, property, &data) >= 0) {
if (data == kApplication)
return this;
BMessage reply(B_MESSAGE_NOT_UNDERSTOOD);
reply.AddInt32("error", B_ERROR);
reply.AddString("message", "Unkown specifier.");
message->SendReply(&reply);
return NULL;
}
return BApplication::ResolveSpecifier(message, index, specifier, what,
property);
}
status_t
AutoMounter::GetSupportedSuites(BMessage* data)
{
if (data == NULL)
return B_BAD_VALUE;
status_t status = data->AddString("suites",
"suite/vnd.Haiku-mount_server");
if (status != B_OK)
return status;
BPropertyInfo propertyInfo(sPropertyInfo);
status = data->AddFlat("messages", &propertyInfo);
if (status != B_OK)
return status;
return BApplication::GetSupportedSuites(data);
}
bool
AutoMounter::_ScriptReceived(BMessage *message, int32 index,
BMessage *specifier, int32 what, const char *property)
{
BMessage reply(B_REPLY);
status_t err = B_BAD_SCRIPT_SYNTAX;
switch (message->what) {
case B_EXECUTE_PROPERTY:
if (strcmp("InitialScan", property) == 0) {
printf("performing initial scan.\n");
_MountVolumes(fNormalMode, fRemovableMode, true);
err = reply.AddString("result", "Previous volumes mounted.");
}
break;
}
if (err == B_BAD_SCRIPT_SYNTAX)
return false;
if (err != B_OK) {
reply.what = B_MESSAGE_NOT_UNDERSTOOD;
reply.AddString("message", strerror(err));
}
reply.AddInt32("error", err);
message->SendReply(&reply);
return true;
}
// #pragma mark -
static bool
suggest_mount_flags(const BPartition* partition, uint32* _flags)
{
uint32 mountFlags = 0;
bool askReadOnly = true;
bool isBFS = false;
if (partition->ContentType() != NULL
&& strcmp(partition->ContentType(), kPartitionTypeBFS) == 0) {
#if 0
askReadOnly = false;
#endif
isBFS = true;
}
BDiskSystem diskSystem;
status_t status = partition->GetDiskSystem(&diskSystem);
if (status == B_OK && !diskSystem.SupportsWriting())
askReadOnly = false;
if (partition->IsReadOnly())
askReadOnly = false;
if (askReadOnly) {
// Suggest to the user to mount read-only until Haiku is more mature.
BString string;
string << "Mounting volume ";
if (partition->ContentName() != NULL)
string << "'" << partition->ContentName() << "'\n\n";
else
string << "<unnamed volume>\n\n";
// TODO: Use distro name instead of "Haiku"...
if (!isBFS) {
string << "The file system on this volume is not the Haiku file "
"system. It is strongly suggested to mount it in read-only "
"mode. ";
} else {
string << "It is suggested to mount all additional Haiku volumes "
"in read-only mode. ";
}
string << "This will prevent unintentional data loss because of "
"errors in Haiku.";
BAlert* alert = new BAlert("Mount Warning", string.String(),
"Mount Read/Write", "Cancel", "Mount Read-only",
B_WIDTH_FROM_WIDEST, B_WARNING_ALERT);
alert->SetShortcut(1, B_ESCAPE);
int32 choice = alert->Go();
switch (choice) {
case 0:
break;
case 1:
return false;
case 2:
mountFlags |= B_MOUNT_READ_ONLY;
break;
}
}
*_flags = mountFlags;
return true;
}
void
AutoMounter::_MountVolumes(mount_mode normal, mount_mode removable,
bool initialRescan, partition_id deviceID)
{
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 (!suggest_mount_flags(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
&& partition->GetMountPoint(&path) == B_OK) {
// notify Tracker that a new volume has been started
BMessage note(kVolumeMounted);
note.AddString("path", path.Path());
note.AddBool("initial rescan", fInitialRescan);
be_app->PostMessage(&note);
}
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);
}
void
AutoMounter::_MountVolume(const BMessage* message)
{
int32 id;
if (message->FindInt32("id", &id) != B_OK)
return;
BDiskDeviceRoster roster;
BPartition *partition;
BDiskDevice device;
if (roster.GetPartitionWithID(id, &device, &partition) != B_OK)
return;
uint32 mountFlags;
if (!suggest_mount_flags(partition, &mountFlags))
return;
status_t status = partition->Mount(NULL, mountFlags);
if (status < B_OK) {
BString string;
string << "Error mounting volume. (" << strerror(status) << ")";
(new BAlert("", string.String(), "Ok"))->Go(NULL);
}
}
bool
AutoMounter::_SuggestForceUnmount(const char* name, status_t error)
{
BString text;
text << "Could not unmount disk \"" << name << "\":\n\t";
text << strerror(error);
text << "\n\nShould unmounting be forced?\n\n"
"Note: if an application is currently writing to the volume, "
"unmounting it now might result in loss of data.\n";
BAlert* alert = new BAlert("", text.String(), "Cancel", "Force Unmount",
NULL, B_WIDTH_AS_USUAL, B_WARNING_ALERT);
alert->SetShortcut(0, B_ESCAPE);
int32 choice = alert->Go();
return choice == 1;
}
void
AutoMounter::_ReportUnmountError(const char* name, status_t error)
{
BString text;
text << "Could not unmount disk \"" << name << "\":\n\t";
text << strerror(error);
(new BAlert("", text.String(), "OK", NULL, NULL, B_WIDTH_AS_USUAL,
B_WARNING_ALERT))->Go(NULL);
}
void
AutoMounter::_UnmountAndEjectVolume(BPartition* partition, BPath& mountPoint,
const char* name)
{
BDiskDevice device;
if (partition == NULL) {
// Try to retrieve partition
BDiskDeviceRoster().FindPartitionByMountPoint(mountPoint.Path(),
&device, &partition);
}
status_t status;
if (partition != NULL)
status = partition->Unmount();
else
status = fs_unmount_volume(mountPoint.Path(), 0);
if (status < B_OK) {
if (!_SuggestForceUnmount(name, status))
return;
if (partition != NULL)
status = partition->Unmount(B_FORCE_UNMOUNT);
else
status = fs_unmount_volume(mountPoint.Path(), B_FORCE_UNMOUNT);
}
if (status < B_OK) {
_ReportUnmountError(partition->ContentName(), status);
return;
}
if (fEjectWhenUnmounting && partition != NULL) {
// eject device if it doesn't have any mounted partitions left
class IsMountedVisitor : public BDiskDeviceVisitor {
public:
IsMountedVisitor()
:
fHasMounted(false)
{
}
virtual bool Visit(BDiskDevice* device)
{
return Visit(device, 0);
}
virtual bool Visit(BPartition* partition, int32 level)
{
if (partition->IsMounted()) {
fHasMounted = true;
return true;
}
return false;
}
bool HasMountedPartitions() const
{
return fHasMounted;
}
private:
bool fHasMounted;
} visitor;
partition->Device()->VisitEachDescendant(&visitor);
if (!visitor.HasMountedPartitions())
partition->Device()->Eject();
}
// remove the directory if it's a directory in rootfs
if (dev_for_path(mountPoint.Path()) == dev_for_path("/"))
rmdir(mountPoint.Path());
}
void
AutoMounter::_UnmountAndEjectVolume(BMessage* message)
{
int32 id;
if (message->FindInt32("id", &id) == B_OK) {
BDiskDeviceRoster roster;
BPartition *partition;
BDiskDevice device;
if (roster.GetPartitionWithID(id, &device, &partition) != B_OK)
return;
BPath path;
if (partition->GetMountPoint(&path) == B_OK)
_UnmountAndEjectVolume(partition, path, partition->ContentName());
} else {
// see if we got a dev_t
dev_t device;
if (message->FindInt32("device_id", &device) != B_OK)
return;
BVolume volume(device);
status_t status = volume.InitCheck();
char name[B_FILE_NAME_LENGTH];
if (status == B_OK)
status = volume.GetName(name);
if (status < B_OK)
snprintf(name, sizeof(name), "device:%ld", device);
BPath path;
if (status == B_OK) {
BDirectory mountPoint;
status = volume.GetRootDirectory(&mountPoint);
if (status == B_OK)
status = path.SetTo(&mountPoint, ".");
}
if (status == B_OK)
_UnmountAndEjectVolume(NULL, path, name);
}
}
void
AutoMounter::_FromMode(mount_mode mode, bool& all, bool& bfs, bool& restore)
{
all = bfs = restore = false;
switch (mode) {
case kAllVolumes:
all = true;
break;
case kOnlyBFSVolumes:
bfs = true;
break;
case kRestorePreviousVolumes:
restore = true;
break;
default:
break;
}
}
AutoMounter::mount_mode
AutoMounter::_ToMode(bool all, bool bfs, bool restore)
{
if (all)
return kAllVolumes;
if (bfs)
return kOnlyBFSVolumes;
if (restore)
return kRestorePreviousVolumes;
return kNoVolumes;
}
void
AutoMounter::_ReadSettings()
{
BPath directoryPath;
if (find_directory(B_USER_SETTINGS_DIRECTORY, &directoryPath, true)
!= B_OK) {
return;
}
BPath path(directoryPath);
path.Append(kMountServerSettings);
fPrefsFile.SetTo(path.Path(), O_RDWR);
if (fPrefsFile.InitCheck() != B_OK) {
// no prefs file yet, create a new one
BDirectory dir(directoryPath.Path());
dir.CreateFile(kMountServerSettings, &fPrefsFile);
return;
}
ssize_t settingsSize = (ssize_t)fPrefsFile.Seek(0, SEEK_END);
if (settingsSize == 0)
return;
ASSERT(settingsSize != 0);
char *buffer = new(std::nothrow) char[settingsSize];
if (buffer == NULL) {
PRINT(("error writing automounter settings, out of memory\n"));
return;
}
fPrefsFile.Seek(0, 0);
if (fPrefsFile.Read(buffer, (size_t)settingsSize) != settingsSize) {
PRINT(("error reading automounter settings\n"));
delete [] buffer;
return;
}
BMessage message('stng');
status_t result = message.Unflatten(buffer);
if (result != B_OK) {
PRINT(("error %s unflattening automounter settings, size %d\n",
strerror(result), settingsSize));
delete [] buffer;
return;
}
delete [] buffer;
// update flags and modes from the message
_UpdateSettingsFromMessage(&message);
// copy the previously mounted partitions
fSettings = message;
}
void
AutoMounter::_WriteSettings()
{
if (fPrefsFile.InitCheck() != B_OK)
return;
BMessage message('stng');
_GetSettings(&message);
ssize_t settingsSize = message.FlattenedSize();
char *buffer = new(std::nothrow) char[settingsSize];
if (buffer == NULL) {
PRINT(("error writing automounter settings, out of memory\n"));
return;
}
status_t result = message.Flatten(buffer, settingsSize);
fPrefsFile.Seek(0, SEEK_SET);
result = fPrefsFile.Write(buffer, (size_t)settingsSize);
if (result != settingsSize)
PRINT(("error writing automounter settings, %s\n", strerror(result)));
delete [] buffer;
}
void
AutoMounter::_UpdateSettingsFromMessage(BMessage* message)
{
// auto mounter settings
bool all, bfs, restore;
if (message->FindBool("autoMountAll", &all) != B_OK)
all = true;
if (message->FindBool("autoMountAllBFS", &bfs) != B_OK)
bfs = false;
fRemovableMode = _ToMode(all, bfs, false);
// initial mount settings
if (message->FindBool("initialMountAll", &all) != B_OK)
all = false;
if (message->FindBool("initialMountAllBFS", &bfs) != B_OK)
bfs = false;
if (message->FindBool("initialMountRestore", &restore) != B_OK)
restore = true;
fNormalMode = _ToMode(all, bfs, restore);
// eject settings
bool eject;
if (message->FindBool("ejectWhenUnmounting", &eject) == B_OK)
fEjectWhenUnmounting = eject;
}
void
AutoMounter::_GetSettings(BMessage *message)
{
message->MakeEmpty();
bool all, bfs, restore;
_FromMode(fNormalMode, all, bfs, restore);
message->AddBool("initialMountAll", all);
message->AddBool("initialMountAllBFS", bfs);
message->AddBool("initialMountRestore", restore);
_FromMode(fRemovableMode, all, bfs, restore);
message->AddBool("autoMountAll", all);
message->AddBool("autoMountAllBFS", bfs);
message->AddBool("ejectWhenUnmounting", fEjectWhenUnmounting);
// 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);
}
}
}
// #pragma mark -
int
main(int argc, char* argv[])
{
AutoMounter app;
app.Run();
return 0;
}

View File

@ -0,0 +1,74 @@
/*
* Copyright 2007-2009, Haiku, Inc. All rights reserved.
* Distributed under the terms of the MIT License.
*/
#ifndef AUTO_MOUNTER_H
#define AUTO_MOUNTER_H
#include <Application.h>
#include <DiskDeviceDefs.h>
#include <File.h>
#include <Message.h>
class BPartition;
class BPath;
class AutoMounter : public BApplication {
public:
AutoMounter();
virtual ~AutoMounter();
virtual void MessageReceived(BMessage* message);
virtual bool QuitRequested();
virtual BHandler* ResolveSpecifier(BMessage* message,
int32 index, BMessage* specifier,
int32 what, const char* property);
virtual status_t GetSupportedSuites(BMessage* data);
private:
enum mount_mode {
kNoVolumes,
kOnlyBFSVolumes,
kAllVolumes,
kRestorePreviousVolumes
};
void _GetSettings(BMessage* message);
bool _ScriptReceived(BMessage* msg, int32 index,
BMessage* specifier, int32 form,
const char* property);
void _MountVolumes(mount_mode normal,
mount_mode removable,
bool initialRescan = false,
partition_id deviceID = -1);
void _MountVolume(const BMessage* message);
bool _SuggestForceUnmount(const char* name,
status_t error);
void _ReportUnmountError(const char* name,
status_t error);
void _UnmountAndEjectVolume(BPartition* partition,
BPath& mountPoint, const char* name);
void _UnmountAndEjectVolume(BMessage* message);
void _FromMode(mount_mode mode, bool& all,
bool& bfs, bool& restore);
mount_mode _ToMode(bool all, bool bfs,
bool restore = false);
void _UpdateSettingsFromMessage(BMessage* message);
void _ReadSettings();
void _WriteSettings();
private:
mount_mode fNormalMode;
mount_mode fRemovableMode;
bool fEjectWhenUnmounting;
BFile fPrefsFile;
BMessage fSettings;
};
#endif // AUTO_MOUNTER_H

14
src/servers/mount/Jamfile Normal file
View File

@ -0,0 +1,14 @@
SubDir HAIKU_TOP src servers mount ;
UsePrivateHeaders mount shared storage ;
Server mount_server
:
AutoMounter.cpp
# AutoMounterSettings.cpp
:
libbe.so
$(TARGET_LIBSTDC++)
:
mount_server.rdef
;

View File

@ -0,0 +1,57 @@
/*
* mount_server.rdef
*/
resource app_signature "application/x-vnd.Haiku-mount_server";
resource app_flags B_SINGLE_LAUNCH | B_BACKGROUND_APP;
resource app_version {
major = 1,
middle = 0,
minor = 0,
variety = B_APPV_ALPHA,
internal = 0,
short_info = "mount_server",
long_info = "mount_server ©2009 Haiku"
};
resource vector_icon array {
$"6E6369661603010000020016023CC7EE389BC0BA16573E39B04A25E4468B7100"
$"FFFFD3020016023C5A743B25DEBC0A703D0D214B89B149B4E00047FF9E020016"
$"02396BD8394C21BC8C213CA4A24C06D7486315003DFF8102001602BC592FBB29"
$"A73C0CE4BD0B7C4892C04B9966007DFFD40200060238DBB4399733BC4A333BA5"
$"424866664A1B3D00596756FFEBB2B203A7FF0003FF0000040180020006023F20"
$"000000000000003E3000C000000000005BF8F8FFFF5D5BBB020006023A6FFE3A"
$"7CC1BD2F743D1F1D4AACC540BDFEA0372874E4151EC8020006023EAF513C0E74"
$"BAAEAE3D808045F168C49DEB63FFFFFFE8878CE4020016023E72000000000000"
$"003D8000BF800041C00000C5C8FF020006023C67EC3DCD85BDA9DD3C515E49AD"
$"B5C589F5A7837BBDEFD4D5F5020006023F30000000000000003DC000C0000042"
$"000000231587FFDBE2E7020006023E12000000000000003BD00046B000420000"
$"9AF8FCC6FFFBF8A302000602400000000000000000400000C000004200000082"
$"82FDFF124DA702000602400000000000000000400000C0000042000000FFFFFF"
$"FFE8E2E202030605B812A5BE03E13DE784B802104A6BCF479BB000F1F1F136D9"
$"DDF48A9996B9B4B8BEDBFFF4F4F4038B86B803837FA802011602B7AF7C3CA0E1"
$"BF1E0BBA2F7E4A3050487E9E0046FFDA170605E202405F46C949C4CE6045604A"
$"60415C400A062240224D405D5A435A363D2C0A062240404DC73BBE4F5A363D2C"
$"B67B3B0607EA283D2C5A36C73BBE4F483E4E3E423E403A42B67B3B0607EA2822"
$"40404DC73BBE4F483E4E3E423E403A42B67B3B0A04404D405DC746C3C7C746BE"
$"450A04C746C3C75A435A36C746BE450A042240224D405D404D08022747B814C3"
$"8908022647294802044626C76B26BCDC262E302EB72C2EBB93463ABCDC3AC76B"
$"3A5E305EBB935EB72C0608BFFE4626C76B26BCDC262E302EB72C2EBAB7BC9DBC"
$"A0BA2BBBE7BC9DBCA04A2E4C30BF67BD31BF67BD31C045BD4D463AC1303AC76B"
$"3A5E305EBB935EB72C0604BE4A2EBC9DBCA0BC9DBCA0BD74BCE0BF67BD31BE64"
$"BD11BF67BD314C300204462BC3E62BC0612BBEF32EBEF3B7EBBEF3B93C4631C0"
$"6131C3E6314E2E4EB93C4EB7EB0A0621302133393C4B2E4B2B33250A044B2B4B"
$"2E393B39380A04213321303938393B0A0627322D2E2E2E3731373232360A042A"
$"322E2F30302C330806353A35373C322D2D273127340A0427322735323932360A"
$"04BC03B57DB920B73BBE01B8C7C131B6C9080435262D2BBEDAB920462A180A08"
$"0100000A0001011001178400040A010104000A150103000A020105000A030106"
$"000A040107000A0501081001178520040A0701093024B39901178200040A0601"
$"093020B2E601178200040A00010A1001178400040A13010C000A12010B000A14"
$"010D1001178100040A09010E000A0A010F000A0B0110000A0C0111000A100112"
$"000A0E01131001178100040A110114000A0D01161001178100040A0F0115000A"
$"00010E100117820004"
};