Beispiel #1
0
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() ;
}
Beispiel #2
0
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 ;
				}
			}
		}
	}
}