Changeset 19893

Show
Ignore:
Timestamp:
01/21/07 13:03:47 (22 months ago)
Author:
axeld
Message:

* Implemented the AutoMounter for Haiku - it's barely tested at this point, but

at least mounting/unmounting seems to work. This fixes bug #191.

* Also changed the way how Tracker automatically mounts/unmounts volumes: it now

only differentiates between removable and fixed storage, not between initial
scan at boot, and periodical scans during runtime. Also removed all HFS stuff.

* Got rid of _INCLUDES_CLASS_DEVICE_MAP for the BeOS build.

Location:
haiku/trunk/src/kits/tracker
Files:
2 modified

Legend:

Unmodified
Added
Removed
  • haiku/trunk/src/kits/tracker/AutoMounter.cpp

    r17944 r19893  
    4141#include "Tracker.h" 
    4242#include "TrackerSettings.h" 
     43 
     44#ifdef __HAIKU__ 
     45#       include <DiskDeviceRoster.h> 
     46#       include <DiskDevice.h> 
     47#       include <DiskDeviceList.h> 
     48#       include <fs_volume.h> 
     49#endif 
    4350 
    4451#include <Alert.h> 
     
    5360 
    5461 
     62static const char *kAutoMounterSettings = "automounter_settings"; 
     63 
     64 
     65#ifdef __HAIKU__ 
     66//      #pragma mark - Haiku Disk Device API 
     67 
     68static const uint32 kMsgInitialScan = 'insc'; 
     69 
     70 
     71AutoMounter::AutoMounter() 
     72        : BLooper("AutoMounter", B_LOW_PRIORITY), 
     73        fNormalMode(kRestorePreviousVolumes), 
     74        fRemovableMode(kAllVolumes) 
     75{ 
     76        if (!BootedInSafeMode()) { 
     77                _ReadSettings(); 
     78        } else { 
     79                // defeat automounter in safe mode, don't even care about the settings 
     80                fNormalMode = kNoVolumes; 
     81                fRemovableMode = kNoVolumes; 
     82        } 
     83 
     84        if (PostMessage(kMsgInitialScan) != B_OK) 
     85                debug_printf("AutoMounter: OH NO!\n"); 
     86} 
     87 
     88 
     89AutoMounter::~AutoMounter() 
     90{ 
     91} 
     92 
     93 
     94void 
     95AutoMounter::_MountVolumes(mount_mode normal, mount_mode removable) 
     96{ 
     97        if (normal == kNoVolumes && removable == kNoVolumes) 
     98                return; 
     99 
     100        class InitialMountVisitor : public BDiskDeviceVisitor { 
     101                public: 
     102                        InitialMountVisitor(mount_mode normalMode, mount_mode removableMode, 
     103                                        BMessage& previous) 
     104                                : 
     105                                fNormalMode(normalMode), 
     106                                fRemovableMode(removableMode), 
     107                                fPrevious(previous) 
     108                        { 
     109                        } 
     110 
     111                        virtual 
     112                        ~InitialMountVisitor() 
     113                        { 
     114                        } 
     115 
     116                        virtual bool 
     117                        Visit(BDiskDevice* device) 
     118                        { 
     119                                return Visit(device, 0); 
     120                        } 
     121 
     122                        virtual bool 
     123                        Visit(BPartition* partition, int32 level) 
     124                        { 
     125                                mount_mode mode = partition->Device()->IsRemovableMedia() 
     126                                        ? fRemovableMode : fNormalMode; 
     127                                if (mode == kNoVolumes 
     128                                        || partition->IsMounted() 
     129                                        || !partition->ContainsFileSystem()) 
     130                                        return false; 
     131 
     132                                if (mode == kRestorePreviousVolumes) { 
     133                                        // mount all volumes that were stored in the settings file 
     134                                        const char *volumeName; 
     135                                        BPath path; 
     136                                        if (partition->GetPath(&path) != B_OK 
     137                                                || partition->ContentName() == NULL 
     138                                                || fPrevious.FindString(path.Path(), &volumeName) != B_OK 
     139                                                || strcmp(volumeName, partition->ContentName())) 
     140                                                return false; 
     141                                } else if (mode == kOnlyBFSVolumes) { 
     142                                        if (partition->ContentType() == NULL 
     143                                                || strcmp(partition->ContentType(), "BFS")) 
     144                                                return false; 
     145                                } 
     146 
     147                                partition->Mount(); 
     148                                return false; 
     149                        } 
     150 
     151                private: 
     152                        mount_mode      fNormalMode; 
     153                        mount_mode      fRemovableMode; 
     154                        BMessage&       fPrevious; 
     155        } visitor(normal, removable, fSettings); 
     156 
     157        BDiskDeviceList devices; 
     158        status_t status = devices.Fetch(); 
     159        if (status == B_OK) 
     160                devices.VisitEachPartition(&visitor); 
     161} 
     162 
     163 
     164void 
     165AutoMounter::_MountVolume(BMessage *message) 
     166{ 
     167        int32 id; 
     168        if (message->FindInt32("id", &id) != B_OK) 
     169                return; 
     170 
     171        BDiskDeviceRoster roster; 
     172        BPartition *partition; 
     173        BDiskDevice device; 
     174        if (roster.GetPartitionWithID(id, &device, &partition) != B_OK) 
     175                return; 
     176 
     177        status_t status = partition->Mount(); 
     178        if (status < B_OK) { 
     179                BString string; 
     180                string << "Error mounting volume. (" << strerror(status) << ")"; 
     181                        (new BAlert("", string.String(), "OK"))->Go(0); 
     182        } 
     183} 
     184 
     185 
     186bool 
     187AutoMounter::_ForceUnmount(const char* name, status_t error) 
     188{ 
     189        BString text; 
     190        text << "Could not unmount disk \"" << name << "\":\n\t" << strerror(error); 
     191        text << "\n\nShould I force unmounting the disk?\n\n" 
     192                "Note: if an application is currently writing to the volume, unmounting" 
     193                " it now might result in loss of data.\n"; 
     194 
     195        int32 choice = (new BAlert("", text.String(), "Cancel", "Force Unmount", NULL, 
     196                B_WIDTH_AS_USUAL, B_WARNING_ALERT))->Go(); 
     197 
     198        return choice == 1; 
     199} 
     200 
     201 
     202void 
     203AutoMounter::_ReportUnmountError(const char* name, status_t error) 
     204{ 
     205        BString text; 
     206        text << "Could not unmount disk \"" << name << "\":\n\t" << strerror(error); 
     207 
     208        (new BAlert("", text.String(), "OK", NULL, NULL, B_WIDTH_AS_USUAL,  
     209                B_WARNING_ALERT))->Go(NULL); 
     210} 
     211 
     212 
     213void 
     214AutoMounter::_UnmountAndEjectVolume(BMessage *message) 
     215{ 
     216        int32 id; 
     217        if (message->FindInt32("id", &id) == B_OK) { 
     218                BDiskDeviceRoster roster; 
     219                BPartition *partition; 
     220                BDiskDevice device; 
     221                if (roster.GetPartitionWithID(id, &device, &partition) != B_OK) 
     222                        return; 
     223 
     224                status_t status = partition->Unmount(); 
     225                if (status < B_OK) { 
     226                        if (!_ForceUnmount(partition->ContentName(), status)) 
     227                                return; 
     228 
     229                        status = partition->Unmount(B_FORCE_UNMOUNT); 
     230                } 
     231 
     232                if (status < B_OK) 
     233                        _ReportUnmountError(partition->ContentName(), status); 
     234 
     235                return; 
     236        } 
     237 
     238        // see if we got a dev_t 
     239 
     240        dev_t device; 
     241        if (message->FindInt32("device_id", &device) != B_OK) 
     242                return; 
     243 
     244        BVolume volume(device); 
     245        status_t status = volume.InitCheck(); 
     246 
     247        char name[B_FILE_NAME_LENGTH]; 
     248        if (status == B_OK) 
     249                status = volume.GetName(name); 
     250        if (status < B_OK) 
     251                snprintf(name, sizeof(name), "device:%ld", device); 
     252 
     253        BDirectory mountPoint; 
     254        if (status == B_OK) 
     255                status = volume.GetRootDirectory(&mountPoint); 
     256 
     257        BPath path; 
     258        if (status == B_OK) 
     259                status = path.SetTo(&mountPoint, "."); 
     260 
     261        if (status == B_OK) { 
     262                status = fs_unmount_volume(path.Path(), 0); 
     263                if (status < B_OK) { 
     264                        if (!_ForceUnmount(name, status)) 
     265                                return; 
     266 
     267                        status = fs_unmount_volume(path.Path(), B_FORCE_UNMOUNT); 
     268                } 
     269        } 
     270 
     271        if (status == B_OK) 
     272                rmdir(path.Path()); 
     273 
     274        if (status < B_OK) 
     275                _ReportUnmountError(name, status); 
     276} 
     277 
     278 
     279void 
     280AutoMounter::_FromMode(mount_mode mode, bool& all, bool& bfs, bool& restore) 
     281{ 
     282        all = bfs = restore = false; 
     283 
     284        switch (mode) { 
     285                case kAllVolumes: 
     286                        all = true; 
     287                        break; 
     288                case kOnlyBFSVolumes: 
     289                        bfs = true; 
     290                        break; 
     291                case kRestorePreviousVolumes: 
     292                        restore = true; 
     293                        break; 
     294 
     295                default: 
     296                        break; 
     297        } 
     298} 
     299 
     300 
     301AutoMounter::mount_mode 
     302AutoMounter::_ToMode(bool all, bool bfs, bool restore) 
     303{ 
     304        if (all) 
     305                return kAllVolumes; 
     306        if (bfs) 
     307                return kOnlyBFSVolumes; 
     308        if (restore) 
     309                return kRestorePreviousVolumes; 
     310 
     311        return kNoVolumes; 
     312} 
     313 
     314 
     315void 
     316AutoMounter::_ReadSettings() 
     317{ 
     318        BPath directoryPath; 
     319        if (FSFindTrackerSettingsDir(&directoryPath) != B_OK) 
     320                return; 
     321 
     322        BPath path(directoryPath); 
     323        path.Append(kAutoMounterSettings); 
     324        fPrefsFile.SetTo(path.Path(), O_RDWR); 
     325 
     326        if (fPrefsFile.InitCheck() != B_OK) { 
     327                // no prefs file yet, create a new one 
     328 
     329                BDirectory dir(directoryPath.Path()); 
     330                dir.CreateFile(kAutoMounterSettings, &fPrefsFile); 
     331                return; 
     332        } 
     333 
     334        ssize_t settingsSize = (ssize_t)fPrefsFile.Seek(0, SEEK_END); 
     335        if (settingsSize == 0) 
     336                return; 
     337 
     338        ASSERT(settingsSize != 0); 
     339        char *buffer = new char[settingsSize]; 
     340 
     341        fPrefsFile.Seek(0, 0); 
     342        if (fPrefsFile.Read(buffer, (size_t)settingsSize) != settingsSize) { 
     343                PRINT(("error reading automounter settings\n")); 
     344                delete [] buffer; 
     345                return; 
     346        } 
     347 
     348        BMessage message('stng'); 
     349        status_t result = message.Unflatten(buffer); 
     350        if (result != B_OK) { 
     351                PRINT(("error %s unflattening settings, size %d\n", strerror(result),  
     352                        settingsSize)); 
     353                delete [] buffer; 
     354                return; 
     355        } 
     356 
     357        delete [] buffer; 
     358 
     359        _UpdateSettingsFromMessage(&message); 
     360        GetSettings(&fSettings); 
     361} 
     362 
     363 
     364void 
     365AutoMounter::_WriteSettings() 
     366{ 
     367        if (fPrefsFile.InitCheck() != B_OK) 
     368                return; 
     369 
     370        BMessage message('stng'); 
     371        GetSettings(&message); 
     372 
     373        ssize_t settingsSize = message.FlattenedSize(); 
     374 
     375        char *buffer = new char[settingsSize]; 
     376        status_t result = message.Flatten(buffer, settingsSize); 
     377 
     378        fPrefsFile.Seek(0, 0); 
     379        result = fPrefsFile.Write(buffer, (size_t)settingsSize); 
     380        if (result != settingsSize) 
     381                PRINT(("error writing settings, %s\n", strerror(result))); 
     382 
     383        delete [] buffer; 
     384} 
     385 
     386 
     387void 
     388AutoMounter::_UpdateSettingsFromMessage(BMessage* message) 
     389{ 
     390        // auto mounter settings 
     391 
     392        bool all, bfs, restore; 
     393        if (message->FindBool("autoMountAll", &all) != B_OK) 
     394                all = true; 
     395        if (message->FindBool("autoMountAllBFS", &bfs) != B_OK) 
     396                bfs = false; 
     397 
     398        fRemovableMode = _ToMode(all, bfs, false); 
     399 
     400        // initial mount settings 
     401 
     402        if (message->FindBool("initialMountAll", &all) != B_OK) 
     403                all = false; 
     404        if (message->FindBool("initialMountAllBFS", &bfs) != B_OK) 
     405                bfs = false; 
     406        if (message->FindBool("initialMountRestore", &restore) != B_OK) 
     407                restore = true; 
     408 
     409        fNormalMode = _ToMode(all, bfs, restore); 
     410} 
     411 
     412 
     413void 
     414AutoMounter::GetSettings(BMessage *message) 
     415{ 
     416        message->MakeEmpty(); 
     417 
     418        bool all, bfs, restore; 
     419 
     420        _FromMode(fNormalMode, all, bfs, restore); 
     421        message->AddBool("initialMountAll", all); 
     422        message->AddBool("initialMountAllBFS", bfs); 
     423        message->AddBool("initialMountRestore", restore); 
     424 
     425        _FromMode(fRemovableMode, all, bfs, restore); 
     426        message->AddBool("autoMountAll", all); 
     427        message->AddBool("autoMountAllBFS", bfs); 
     428 
     429        // Save mounted volumes so we can optionally mount them on next 
     430        // startup 
     431        BVolumeRoster volumeRoster; 
     432        BVolume volume; 
     433        while (volumeRoster.GetNextVolume(&volume) == B_OK) { 
     434        fs_info info; 
     435        if (fs_stat_dev(volume.Device(), &info) == 0 
     436                        && info.flags & (B_FS_IS_REMOVABLE | B_FS_IS_PERSISTENT)) 
     437                        message->AddString(info.device_name, info.volume_name); 
     438        } 
     439} 
     440 
     441 
     442void 
     443AutoMounter::MessageReceived(BMessage *message) 
     444{ 
     445        switch (message->what) { 
     446                case kMsgInitialScan: 
     447                        _MountVolumes(fNormalMode, fRemovableMode); 
     448                        break; 
     449 
     450                case kMountVolume: 
     451                        _MountVolume(message); 
     452                        break; 
     453 
     454                case kUnmountVolume: 
     455                        _UnmountAndEjectVolume(message); 
     456                        break; 
     457 
     458                case kSetAutomounterParams: 
     459                { 
     460                        bool rescanNow = false; 
     461                        message->FindBool("rescanNow", &rescanNow); 
     462 
     463                        _UpdateSettingsFromMessage(message); 
     464                        GetSettings(&fSettings); 
     465                        _WriteSettings(); 
     466 
     467                        if (rescanNow) 
     468                                _MountVolumes(fNormalMode, fRemovableMode); 
     469                        break; 
     470                } 
     471 
     472                case kMountAllNow: 
     473                        _MountVolumes(kAllVolumes, kAllVolumes); 
     474                        break; 
     475 
     476#if 0 
     477                case B_NODE_MONITOR: 
     478                { 
     479                        int32 opcode; 
     480                        if (message->FindInt32("opcode", &opcode) != B_OK) 
     481                                break; 
     482 
     483                        switch (opcode) { 
     484                                //      The name of a mount point has changed 
     485                                case B_ENTRY_MOVED: { 
     486                                        WRITELOG(("*** Received Mount Point Renamed Notification")); 
     487 
     488                                        const char *newName; 
     489                                        if (message->FindString("name", &newName) != B_OK) { 
     490                                                WRITELOG(("ERROR: Couldn't find name field in update message")); 
     491                                                PRINT_OBJECT(*message); 
     492                                                break ; 
     493                                        } 
     494 
     495                                        // 
     496                                        // When the node monitor reports a move, it gives the 
     497                                        // parent device and inode that moved.  The problem is  
     498                                        // that  the inode is the inode of root *in* the filesystem, 
     499                                        // which is generally always the same number for every  
     500                                        // filesystem of a type. 
     501                                        // 
     502                                        // What we'd really like is the device that the moved    
     503                                        // volume is mounted on.  Find this by using the  
     504                                        // *new* name and directory, and then stat()ing that to 
     505                                        // find the device. 
     506                                        // 
     507                                        dev_t parentDevice; 
     508                                        if (message->FindInt32("device", &parentDevice) != B_OK) { 
     509                                                WRITELOG(("ERROR: Couldn't find 'device' field in update" 
     510                                                        " message")); 
     511                                                PRINT_OBJECT(*message); 
     512                                                break; 
     513                                        } 
     514 
     515                                        ino_t toDirectory;       
     516                                        if (message->FindInt64("to directory", &toDirectory)!=B_OK){ 
     517                                                WRITELOG(("ERROR: Couldn't find 'to directory' field in update" 
     518                                                  "message")); 
     519                                                PRINT_OBJECT(*message); 
     520                                                break; 
     521                                        } 
     522 
     523                                        entry_ref root_entry(parentDevice, toDirectory, newName); 
     524 
     525                                        BNode entryNode(&root_entry); 
     526                                        if (entryNode.InitCheck() != B_OK) { 
     527                                                WRITELOG(("ERROR: Couldn't create mount point entry node: %s/n",  
     528                                                        strerror(entryNode.InitCheck()))); 
     529                                                break; 
     530                                        }        
     531 
     532                                        node_ref mountPointNode; 
     533                                        if (entryNode.GetNodeRef(&mountPointNode) != B_OK) { 
     534                                                WRITELOG(("ERROR: Couldn't get node ref for new mount point")); 
     535                                                break; 
     536                                        } 
     537 
     538                                        WRITELOG(("Attempt to rename device %li to %s", mountPointNode.device, 
     539                                                newName)); 
     540 
     541                                        Partition *partition = FindPartition(mountPointNode.device); 
     542                                        if (partition != NULL) { 
     543                                                WRITELOG(("Found device, changing name.")); 
     544 
     545                                                BVolume mountVolume(partition->VolumeDeviceID()); 
     546                                                BDirectory mountDir; 
     547                                                mountVolume.GetRootDirectory(&mountDir); 
     548                                                BPath dirPath(&mountDir, 0); 
     549 
     550                                                partition->SetMountedAt(dirPath.Path()); 
     551                                                partition->SetVolumeName(newName);                                       
     552                                                break; 
     553                                        } else { 
     554                                                WRITELOG(("ERROR: Device %li does not appear to be present", 
     555                                                        mountPointNode.device)); 
     556                                        } 
     557                                } 
     558                        } 
     559                        break; 
     560                } 
     561#endif 
     562 
     563                default: 
     564                        BLooper::MessageReceived(message); 
     565                        break; 
     566        } 
     567} 
     568 
     569 
     570bool 
     571AutoMounter::QuitRequested() 
     572{ 
     573        if (!BootedInSafeMode()) { 
     574                // don't write out settings in safe mode - this would overwrite the 
     575                // normal, non-safe mode settings 
     576                _WriteSettings(); 
     577        } 
     578 
     579        return true; 
     580} 
     581 
     582 
     583#else   // !__HAIKU__ 
     584//      #pragma mark - R5 DeviceMap API 
     585 
    55586static const uint32 kStartPolling = 'strp'; 
    56 #if _INCLUDES_CLASS_DEVICE_MAP 
    57 static const char *kAutoMounterSettings = "automounter_settings"; 
    58 #endif 
     587 
     588static BMessage gSettingsMessage; 
     589static bool gSilentAutoMounter; 
    59590 
    60591struct OneMountFloppyParams { 
    61592        status_t result; 
    62593}; 
    63  
    64 #if _INCLUDES_CLASS_DEVICE_MAP 
    65 static bool gSilentAutoMounter; 
    66 #endif 
    67 static BMessage gSettingsMessage; 
    68  
    69  
    70 #if xDEBUG 
    71 static Partition * 
    72 DumpPartition(Partition *_DEVICE_MAP_ONLY(partition), void*) 
    73 { 
    74 #if _INCLUDES_CLASS_DEVICE_MAP 
    75         partition->Dump(); 
    76 #endif 
    77         return 0; 
    78 } 
    79 #endif 
    80  
    81  
    82 #if _INCLUDES_CLASS_DEVICE_MAP 
    83  
    84594 
    85595struct MountPartitionParams { 
     
    87597        status_t result; 
    88598}; 
     599 
     600 
     601#if xDEBUG 
     602static Partition * 
     603DumpPartition(Partition *partition, void*) 
     604{ 
     605        partition->Dump(); 
     606        return 0; 
     607} 
     608#endif 
    89609 
    90610 
     
    303823 
    304824 
     825struct UnmountDeviceParams { 
     826        dev_t device; 
     827        status_t result; 
     828}; 
     829 
     830 
     831static Partition * 
     832UnmountIfMatchingID(Partition *partition, void *castToParams) 
     833{ 
     834        UnmountDeviceParams *params = (UnmountDeviceParams *)castToParams; 
     835 
     836        if (partition->VolumeDeviceID() == params->device) { 
     837                TTracker *tracker = dynamic_cast<TTracker *>(be_app); 
     838                if (tracker && tracker->QueryActiveForDevice(params->device)) { 
     839                        BString text; 
     840                        text << "To unmount " << partition->VolumeName() << " some query " 
     841                        "windows have to be closed. Would you like to close the query " 
     842                        "windows?"; 
     843                        if ((new BAlert("", text.String(), "Cancel", "Close and unmount", NULL, 
     844                                B_WIDTH_FROM_LABEL))->Go() == 0) 
     845                                return partition; 
     846                        tracker->CloseActiveQueryWindows(params->device); 
     847                } 
     848 
     849                params->result = partition->Unmount(); 
     850                Device *device = partition->GetDevice(); 
     851                bool deviceHasMountedPartitions = false; 
     852 
     853                if (params->result == B_OK && device->Removable()) { 
     854                        for (int32 sessionIndex = 0; ; sessionIndex++) { 
     855                                Session *session = device->SessionAt(sessionIndex); 
     856                                if (!session) 
     857                                        break; 
     858 
     859                                for (int32 partitionIndex = 0; ; partitionIndex++) { 
     860                                        Partition *partition = session->PartitionAt(partitionIndex); 
     861                                        if (!partition) 
     862                                                break; 
     863 
     864                                        if (partition->Mounted() == kMounted) { 
     865                                                deviceHasMountedPartitions = true; 
     866                                                break; 
     867                                        } 
     868                                } 
     869                        } 
     870 
     871                        if (!deviceHasMountedPartitions 
     872                                && TrackerSettings().EjectWhenUnmounting()) 
     873                                params->result = partition->GetDevice()->Eject(); 
     874                } 
     875 
     876                return partition; 
     877        } 
     878 
     879        return NULL; 
     880} 
     881 
     882 
    305883static Partition * 
    306884NotifyFloppyNotMountable(Partition *partition, void *) 
     
    317895 
    318896 
    319 #endif // #if _INCLUDES_CLASS_DEVICE_MAP 
     897static Device * 
     898FindFloppyDevice(Device *device, void *) 
     899{ 
     900        if (device->IsFloppy()) 
     901                return device; 
     902 
     903        return 0; 
     904} 
    320905 
    321906 
     
    352937 
    353938 
    354 AutoMounter::AutoMounter(bool _DEVICE_MAP_ONLY(checkRemovableOnly), 
    355         bool _DEVICE_MAP_ONLY(checkCDs), bool _DEVICE_MAP_ONLY(checkFloppies), 
    356         bool _DEVICE_MAP_ONLY(checkOtherRemovable), bool _DEVICE_MAP_ONLY(autoMountRemovablesOnly), 
    357         bool _DEVICE_MAP_ONLY(autoMountAll), bool _DEVICE_MAP_ONLY(autoMountAllBFS), 
    358         bool _DEVICE_MAP_ONLY(autoMountAllHFS), 
    359         bool initialMountAll, bool initialMountAllBFS, bool initialMountRestore, 
    360         bool initialMountAllHFS)