void MainWindow::startAutoMonitor() { m_mountInfo = new monitor_mountinfo( this ) ; m_autoMountThread = new auto_mount( this ) ; /* * perform an ordely shut down when the application terminates to prevent an occassional crash with * a warning that says something like "an object was destroyed while a thread is still running" * * On quiting,we first shut down auto_mount object and then monitor_mountinfo object and then we * close the application */ connect( m_mountInfo,SIGNAL( stopped() ),this,SLOT( quitApplication() ) ) ; connect( m_autoMountThread,SIGNAL( stopped() ),m_mountInfo,SLOT( stop() ) ) ; connect( m_mountInfo,SIGNAL( volumeRemoved( QString ) ),this,SLOT( removeEntryFromTable( QString ) ) ) ; m_mountInfo->start() ; m_autoMountThread->start() ; }
void monitor_mountinfo::run() { m_mtoto = this ; connect( m_mtoto,SIGNAL( terminated() ),m_main,SLOT( threadStopped() ) ) ; connect( m_mtoto,SIGNAL( terminated() ),m_mtoto,SLOT( deleteLater() ) ) ; Task::FileHandle manage_fd ; int fd = manage_fd( open( "/proc/self/mountinfo",O_RDONLY ) ) ; if( fd == -1 ){ return ; }else{ m_running = true ; } struct pollfd monitor ; monitor.fd = fd ; monitor.events = POLLPRI ; auto _loop = [&](){ poll( &monitor,1,-1 ) ; return 1 ; } ; auto _unmountProperty = [&]( const QString& volume ){ Task * t = new Task() ; t->setDevice( volume ) ; connect( t,SIGNAL( volumeMiniProperties( volumeEntryProperties * ) ), m_babu,SLOT( volumeMiniProperties( volumeEntryProperties * ) ) ) ; connect( t,SIGNAL( volumeRemoved( QString ) ), m_babu,SLOT( volumeRemoved( QString ) ) ) ; t->start( Task::VolumeMiniProperties ) ; } ; auto _mountProperty = [&]( const QString& volume ){ Task * t = new Task() ; t->setDevice( volume ) ; connect( t,SIGNAL( volumeMiniProperties( volumeEntryProperties * ) ), m_babu,SLOT( volumeMiniProperties( volumeEntryProperties * ) ) ) ; t->start( Task::VolumeMiniProperties ) ; } ; QStringList oldMountList = Task::updateVolumeList() ; QStringList newMountList ; auto _volumeWasUnMounted = [&](){ return oldMountList.size() > newMountList.size() ; } ; auto _volumeWasMounted = [&](){ return oldMountList.size() < newMountList.size() ; } ; auto _unmountedVolume = [&]( const QString& e ){ return !newMountList.contains( e ) ; } ; auto _mountedVolume = [&]( const QString& e ){ return !oldMountList.contains( e ) ; } ; while( _loop() ){ newMountList = Task::updateVolumeList() ; if( _volumeWasUnMounted() ){ for( const auto& it : oldMountList ){ if( _unmountedVolume( it ) ){ _unmountProperty( it ) ; } } }else if( _volumeWasMounted() ){ for( const auto& it : newMountList ){ if( _mountedVolume( it ) ){ _mountProperty( it ) ; } } }else{ /* * mount/unmount just happened but volume count remain the same, * possible reason is because of a bind mount */ } oldMountList = newMountList ; } }
void events::run() { m_running = true ; m_mtoto = this ; connect( m_mtoto,SIGNAL( finished() ),m_main,SLOT( threadStopped() ) ) ; connect( m_mtoto,SIGNAL( finished() ),m_mtoto,SLOT( deleteLater() ) ) ; connect( this,SIGNAL( volumeMiniProperties( volumeEntryProperties * ) ), m_babu,SLOT( autoMountVolume( volumeEntryProperties * ) ) ) ; connect( this,SIGNAL( volumeRemoved( QString ) ), m_babu,SLOT( volumeRemoved( QString ) ) ) ; utility::fileHandle f( inotify_init() ) ; int fd = f.handle() ; if( fd == -1 ){ return this->failedToStart() ; } int dev = inotify_add_watch( fd,"/dev",IN_CREATE|IN_DELETE ) ; int dm = inotify_add_watch( fd,"/dev/mapper",IN_CREATE|IN_DELETE ) ; int md = -1 ; if( utility::pathExists( "/dev/dm" ) ){ md = inotify_add_watch( fd,"/dev/md",IN_DELETE ) ; } auto _allowed_device = []( const char * device ){ /* * dont care about these devices. * /dev/sgX seem to be created when a usb device is plugged in * /dev/dm-X are dm devices we dont care about since we will be dealing with them differently */ bool s = _startsWith( device,"sg" ) || _startsWith( device,"dm-" ) || _contains( device,"dev/tmp" ) || _contains( device,"dev-tmp" ) || _contains( device,".tmp.md." ) || _contains( device,"md/md-device-map" ) ; return s == false ; } ; auto _device_action = [&]( const struct inotify_event * event ){ /* * /dev/md/ folder seem to be deleted when the last entry in it is removed and * created before the first entry is added.To account for this,monitor for the * folder creation to start monitoring its contents. */ if( event->wd == dev && event->mask & IN_CREATE ){ if( _stringsAreEqual( "md",event->name ) ){ md = inotify_add_watch( fd,"/dev/md",IN_DELETE ) ; return false ; } } if( event->wd == dev && event->mask & IN_DELETE ){ if( _stringsAreEqual( "md",event->name ) ){ inotify_rm_watch( md,dev ) ; return false ; } } return true ; } ; const char * currentEvent ; const char * end ; constexpr int BUFF_SIZE = 4096 ; char buffer[ BUFF_SIZE ] ; fd_set rfds ; FD_ZERO( &rfds ) ; int select_fd = fd + 1 ; auto _eventsReceived = [ & ](){ /* * we are blocking on select() and not on read() because QThread->terminate() does not seem to * be able to get out of a blocked read() on certain Qt versions. */ auto _gotEvents = [ & ](){ FD_SET( fd,&rfds ) ; return select( select_fd,&rfds,nullptr,nullptr,nullptr ) > 0 ; } ; if( _gotEvents() ){ auto s = read( fd,buffer,BUFF_SIZE ) ; if( s > 0 ){ end = buffer + s ; currentEvent = buffer ; return true ; } } return false ; } ; auto _processEvent = [ & ]( const struct inotify_event * event ){ if( _device_action( event ) && _allowed_device( event->name ) ){ auto _device = [ & ](){ if( event->wd == dm ){ return zuluMountTask::devices::dm_device ; }else if( event->wd == md ){ return zuluMountTask::devices::md_device ; }else{ return zuluMountTask::devices::device ; } } ; zuluMountTask::event e{ _device(),event->mask == IN_CREATE,event->name } ; Task::exec( [ this,e ](){ auto r = zuluMountTask::deviceProperties( e ) ; if( r.volumeRemoved ){ emit volumeRemoved( r.volumeName ) ; }else{ emit volumeMiniProperties( r.entry ) ; } } ) ; } } ; #define _cast( x ) reinterpret_cast< const struct inotify_event * >( currentEvent ) #define _eventSize sizeof( struct inotify_event ) while( true ){ if( _eventsReceived() ){ while( currentEvent < end ){ auto event = _cast( currentEvent ) ; if( event ){ _processEvent( event ) ; currentEvent += _eventSize + event->len ; }else{ currentEvent += _eventSize ; } } } } }