/*************************************************************************** smb4kmounter.cpp - The core class that mounts the shares. ------------------- begin : Die Jun 10 2003 copyright : (C) 2003-2007 by Alexander Reinholdt email : dustpuppy@users.berlios.de ***************************************************************************/ /*************************************************************************** * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation; either version 2 of the License, or * * (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, but * * WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * * General Public License for more details. * * * * You should have received a copy of the GNU General Public License * * along with this program; if not, write to the * * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, * * MA 02110-1301 USA * ***************************************************************************/ // TQt includes #include #include #include #include #include // KDE includes #include #include #include #include // system includes #if !defined(__FreeBSD__) && !defined(__sun) #include #elif defined(__sun) #include #elif defined(__FreeBSD__) #include #include #endif #include #include #include #include #include #ifdef __FreeBSD__ #include #include #include #include #endif // Application specific includes #include "smb4kmounter.h" #include "smb4kmounter_p.h" #include "smb4kauthinfo.h" #include "smb4ksambaoptionsinfo.h" #include "smb4kerror.h" #include "smb4tdeglobal.h" #include "smb4ksambaoptionshandler.h" #include "smb4kpasswordhandler.h" #include "smb4kshare.h" #include "smb4ksettings.h" using namespace Smb4TDEGlobal; Smb4KMounter::Smb4KMounter( TQObject *parent, const char *name ) : TQObject( parent, name ) { m_priv = new Smb4KMounterPrivate; m_proc = new TDEProcess( this, "MounterProcess" ); m_proc->setUseShell( true ); m_working = false; m_queue.setAutoDelete( true ); connect( m_proc, TQT_SIGNAL( processExited( TDEProcess * ) ), this, TQT_SLOT( slotProcessExited( TDEProcess * ) ) ); connect( m_proc, TQT_SIGNAL( receivedStdout( TDEProcess *, char *, int ) ), this, TQT_SLOT( slotReceivedStdout( TDEProcess *, char *, int ) ) ); connect( m_proc, TQT_SIGNAL( receivedStderr( TDEProcess *, char *, int ) ), this, TQT_SLOT( slotReceivedStderr( TDEProcess *, char *, int ) ) ); connect( kapp, TQT_SIGNAL( shutDown() ), this, TQT_SLOT( slotShutdown() ) ); } Smb4KMounter::~Smb4KMounter() { abort(); for ( TQValueList::Iterator it = m_mounted_shares.begin(); it != m_mounted_shares.end(); ++it ) { delete *it; } m_mounted_shares.clear(); delete m_priv; } void Smb4KMounter::init() { m_queue.enqueue( new TQString( TQString( "%1:" ).arg( Import ) ) ); m_queue.enqueue( new TQString( TQString( "%1:" ).arg( Remount ) ) ); startTimer( TIMER_INTERVAL ); } /*************************************************************************** Aborts any action of the mounter. ***************************************************************************/ void Smb4KMounter::abort() { m_queue.clear(); if ( m_proc->isRunning() ) { if ( Smb4KSettings::alwaysUseSuperUser() ) { TQString suid_program; switch( Smb4KSettings::superUserProgram() ) { case Smb4KSettings::EnumSuperUserProgram::Sudo: { suid_program = Smb4KSettings::sudo(); break; } case Smb4KSettings::EnumSuperUserProgram::Super: { suid_program = Smb4KSettings::super(); break; } default: { // FIXME: Throw an error? return; } } TDEProcess proc; proc.setUseShell( true ); proc << TQString( "%1 smb4k_kill %2" ).arg( suid_program ).arg( m_proc->pid() ); proc.start( TDEProcess::DontCare, TDEProcess::NoCommunication ); } else { m_proc->kill(); } } } /*************************************************************************** Mounts recently used shares. ***************************************************************************/ void Smb4KMounter::remount() { if ( Smb4KSettings::remountShares() ) { const TQValueList *list = &(optionsHandler()->customOptionsList()); for ( TQValueList::ConstIterator it = list->begin(); it != list->end(); ++it ) { if ( (*it)->remount() ) { TQValueList list = findShareByName( (*it)->itemName() ); bool mount = true; if ( !list.isEmpty() ) { for ( TQValueList::ConstIterator it = list.begin(); it != list.end(); ++it ) { if ( !(*it).isForeign() ) { mount = false; break; } else { continue; } } } if ( mount ) { #ifndef __FreeBSD__ mountShare( TQString(), (*it)->itemName().section( "/", 2, 2 ), TQString(), (*it)->itemName().section( "/", 3, 3 ) ); #else mountShare( TQString(), (*it)->itemName().section( "/", 2, 2 ).section( "@", 1, 1 ), TQString(), (*it)->itemName().section( "/", 3, 3 ) ); #endif } // If the share is to be remounted the next time, // slotShutdown() will tell the options handler. (*it)->setRemount( false ); continue; } else { continue; } } m_working = false; emit state( MOUNTER_STOP ); } else { m_working = false; emit state( MOUNTER_STOP ); } } /*************************************************************************** Imports all shares, that are mounted externally. ***************************************************************************/ void Smb4KMounter::import() { TQValueList shares; #ifndef __FreeBSD__ if ( m_proc_mounts.name().isEmpty() ) { m_proc_mounts.setName( "/proc/mounts" ); } if ( !TQFile::exists( m_proc_mounts.name() ) ) { if ( !m_proc_error ) { m_proc_error = true; Smb4KError::error( ERROR_FILE_NOT_FOUND, m_proc_mounts.name() ); } else { // No need to do anything here } } else { TQStringList contents, list; // Read /proc/mounts: if ( m_proc_mounts.open( IO_ReadOnly ) ) { TQTextStream ts( &m_proc_mounts ); ts.setEncoding( TQTextStream::Locale ); contents = TQStringList::split( "\n", ts.read(), false ); m_proc_mounts.close(); } else { Smb4KError::error( ERROR_OPENING_FILE, m_proc_mounts.name() ); return; } // Process the SMBFS and CIFS entries: list += contents.grep( " smbfs ", true ); list += contents.grep( " cifs ", true ); if ( !list.isEmpty() ) { for ( TQStringList::Iterator it = list.begin(); it != list.end(); it++ ) { Smb4KShare *new_share = NULL; if ( (*it).contains( " smbfs ", false ) != 0 ) { TQString share_and_path = (*it).section( " smbfs ", 0, 0 ).stripWhiteSpace(); TQString name = share_and_path.section( " ", 0, 0 ).stripWhiteSpace().replace( "\\040", "\040" ); TQString path = share_and_path.section( " ", 1, 1 ).stripWhiteSpace(); if ( path.contains( "\\040" ) != 0 || path.contains( "\040" ) != 0 ) { name.replace( "_", "\040" ); path.replace( "\\040", "\040" ); } int uid = (*it).section( "uid=", 1, 1 ).section( ",", 0, 0 ).stripWhiteSpace().toInt(); int gid = (*it).section( "gid=", 1, 1 ).section( ",", 0, 0 ).stripWhiteSpace().toInt(); new_share = new Smb4KShare( name, path, "smbfs", uid, gid ); } else if ( (*it).contains( " cifs ", false ) != 0 ) { TQString share_and_path = (*it).section( " cifs ", 0, 0 ).stripWhiteSpace(); TQString name = share_and_path.section( " ", 0, 0 ).stripWhiteSpace().replace( "\\040", "\040" ); TQString path = share_and_path.section( " ", 1, 1 ).stripWhiteSpace(); if ( path.contains( "\\040" ) != 0 || path.contains( "\040" ) != 0 ) { name.replace( "_", "\040" ); path.replace( "\\040", "\040" ); } TQString login = (*it).section( "username=", 1, 1 ).section( ",", 0, 0 ).stripWhiteSpace(); new_share = new Smb4KShare( name, path, "cifs", login ); } else { continue; } if ( new_share ) { // If the a representative of the new share is already in the list of // mounted shares, replace the new with the old one. Smb4KShare *existing_share = findShareByPath( new_share->path() ); if ( existing_share ) { delete new_share; new_share = new Smb4KShare( *existing_share ); } // Check if the share is broken and/or foreign. if ( (existing_share && !existing_share->isBroken()) || !existing_share ) { checkAccessibility( new_share ); } else { // Since new_share is a copy of existing_share, we do not need to do // anything here. } if ( !existing_share && TQString::compare( new_share->filesystem(), "cifs" ) == 0 ) { bool foreign = true; if ( (!new_share->isBroken() && (tqstrncmp( new_share->canonicalPath(), TQDir( Smb4KSettings::mountPrefix() ).canonicalPath(), TQDir( Smb4KSettings::mountPrefix() ).canonicalPath().length() ) == 0 || tqstrncmp( new_share->canonicalPath(), TQDir::home().canonicalPath(), TQDir::home().canonicalPath().length() ) == 0)) || (new_share->isBroken() && (tqstrncmp( new_share->path(), TQDir::homeDirPath(), TQDir::homeDirPath().length() ) == 0 || tqstrncmp( new_share->path(), Smb4KSettings::mountPrefix(), Smb4KSettings::mountPrefix().length() ) == 0)) ) { foreign = false; } new_share->setForeign( foreign ); } shares.append( new_share ); } } } } #else struct statfs *buf; int count = getmntinfo( &buf, 0 ); if ( count == 0 ) { int err_code = errno; Smb4KError::error( ERROR_IMPORTING_SHARES, TQString(), strerror( err_code ) ); m_working = false; return; } for ( int i = 0; i < count; ++i ) { if ( !strcmp( buf[i].f_fstypename, "smbfs" ) ) { TQString share_name( buf[i].f_mntfromname ); TQString path( buf[i].f_mntonname ); TQString fs( buf[i].f_fstypename ); TQFileInfo info( TQString( buf[i].f_mntonname )+"/." ); int uid = (int)info.ownerId(); int gid = (int)info.groupId(); Smb4KShare *existing_share = findShareByPath( path ); Smb4KShare *new_share = NULL; if ( existing_share ) { new_share = new Smb4KShare( *existing_share ); } else { new_share = new Smb4KShare( share_name, path, fs, uid, gid ); } // Test if share is broken if ( (existing_share && !existing_share->isBroken()) || !existing_share ) { checkAccessibility( new_share ); } else { // Since new_share is a copy of existing_share, we do not need to do // anything here. } shares.append( new_share ); } } // Apparently, under FreeBSD we do not need to delete // the pointer (see manual page). #endif // Delete all entries of m_mounted_shares. for ( TQValueList::Iterator it = m_mounted_shares.begin(); it != m_mounted_shares.end(); ++it ) { delete *it; } m_mounted_shares.clear(); m_mounted_shares = shares; emit updated(); m_working = false; } /*************************************************************************** Mounts a share. (Public part) ***************************************************************************/ void Smb4KMounter::mountShare( const TQString &workgroup, const TQString &host, const TQString &ip, const TQString &share ) { TQString share_name = TQString(); if ( TQString::compare( share, "homes" ) == 0 ) { share_name = specifyUser( host, kapp->mainWidget() ? kapp->mainWidget() : 0, "SpecifyUser" ); } else { share_name = share; } if ( !share_name.stripWhiteSpace().isEmpty() ) { // Before doing anything else let's check that the // share has not been mounted by the user already: TQValueList list = findShareByName( TQString( "//%1/%2" ).arg( host, share_name ) ); for ( TQValueList::ConstIterator it = list.begin(); it != list.end(); ++it ) { if ( !(*it).isForeign() ) { emit mountedShare( (*it).canonicalPath() ); return; } } m_queue.enqueue( new TQString( TQString( "%1:%2:%3:%4:%5" ).arg( Mount ) .arg( workgroup, host ) .arg( ip, share_name ) ) ); } } /*************************************************************************** Mounts a share. (Private part) ***************************************************************************/ void Smb4KMounter::mount( const TQString &workgroup, const TQString &host, const TQString &ip, const TQString &share ) { m_priv->setWorkgroup( workgroup ); m_priv->setHost( host ); m_priv->setShare( share ); m_priv->setIP( ip ); // Create the mount point: TQDir *dir = new TQDir( Smb4KSettings::mountPrefix() ); if ( !dir->exists() ) { if ( !dir->mkdir( dir->canonicalPath() ) ) { Smb4KError::error( ERROR_MKDIR_FAILED, dir->path() ); m_working = false; emit state( MOUNTER_STOP ); return; } } dir->setPath( dir->path() + "/" + (Smb4KSettings::forceLowerCaseSubdirs() ? m_priv->host().lower() : m_priv->host()) ); if ( !dir->exists() ) { if ( !dir->mkdir( dir->canonicalPath() ) ) { Smb4KError::error( ERROR_MKDIR_FAILED, dir->path() ); m_working = false; emit state( MOUNTER_STOP ); return; } } dir->setPath( dir->path() + "/" + (Smb4KSettings::forceLowerCaseSubdirs() ? m_priv->share().lower() : m_priv->share()) ); if ( !dir->exists() ) { if ( !dir->mkdir( dir->canonicalPath() ) ) { Smb4KError::error( ERROR_MKDIR_FAILED, dir->path() ); m_working = false; emit state( MOUNTER_STOP ); return; } } m_priv->setPath( TQDir::cleanDirPath( dir->path() ) ); delete dir; // Now we are prepared to mount the share: TQString command, suid_program; switch ( Smb4KSettings::superUserProgram() ) { case Smb4KSettings::EnumSuperUserProgram::Sudo: { suid_program = "sudo"; break; } case Smb4KSettings::EnumSuperUserProgram::Super: { suid_program = "super"; break; } default: { return; } } Smb4KAuthInfo authInfo( m_priv->workgroup(), m_priv->host(), m_priv->share() ); (void) passwordHandler()->readAuth( &authInfo ); #ifndef __FreeBSD__ // Let's see if the options handler knows the share: Smb4KSambaOptionsInfo *info = optionsHandler()->findItem( TQString( "//%1/%2" ).arg( m_priv->host(), m_priv->share() ), true ); // Determine the file system we have to use: int filesystem; if ( info ) { filesystem = TQString::compare( info->filesystem().lower(), "cifs" ) == 0 ? Smb4KSettings::EnumFilesystem::CIFS : Smb4KSettings::EnumFilesystem::SMBFS; } else { filesystem = Smb4KSettings::filesystem(); } // Compile the mount command: switch ( filesystem ) { case Smb4KSettings::EnumFilesystem::CIFS: { command.append( Smb4KSettings::alwaysUseSuperUser() ? // FIXME: Check if suid program is installed TQString( "%1 smb4k_mount -s -t cifs " ).arg( suid_program ) : "smb4k_mount -n -t cifs " ); command.append( "-o " ); command.append( optionsHandler()->mountOptions( TQString( "//%1/%2" ).arg( m_priv->host(), m_priv->share() ) ) ); command.append( !m_priv->workgroup().stripWhiteSpace().isEmpty() ? TQString( "domain='%1'," ).arg( m_priv->workgroup() ) : "" ); command.append( !m_priv->ip().stripWhiteSpace().isEmpty() ? TQString( "ip=%1," ).arg( m_priv->ip() ) : "" ); command.append( !authInfo.user().isEmpty() ? TQString( "user=%1" ).arg( authInfo.user().data() ) : "guest" ); command.append( " -- " ); command.append( TQString( "//'%1'/'%2' '%3'" ).arg( m_priv->host(), m_priv->share(), m_priv->path() ) ); m_priv->setCIFSLogin( !authInfo.user().isEmpty() ? authInfo.user() : "guest" ); m_priv->setFileSystem( "cifs" ); break; } case Smb4KSettings::EnumFilesystem::SMBFS: { command.append( Smb4KSettings::alwaysUseSuperUser() ? // FIXME: Check if suid program is installed TQString( "%1 smb4k_mount -s -t smbfs " ).arg( suid_program ) : "smb4k_mount -n -t smbfs " ); command.append( "-o " ); command.append( optionsHandler()->mountOptions( TQString( "//%1/%2" ).arg( m_priv->host(), m_priv->share() ) ) ); command.append( !m_priv->workgroup().stripWhiteSpace().isEmpty() ? TQString( "workgroup='%1'," ).arg( m_priv->workgroup() ) : "" ); command.append( !m_priv->ip().stripWhiteSpace().isEmpty() ? TQString( "ip=%1," ).arg( m_priv->ip() ) : "" ); command.append( !authInfo.user().isEmpty() ? TQString( "username=%1" ).arg( authInfo.user().data() ) : "guest" ); command.append( " -- " ); command.append( TQString( "//'%1'/'%2' '%3'" ).arg( m_priv->host(), m_priv->share(), m_priv->path() ) ); m_priv->setFileSystem( "smbfs" ); break; } default: { return; } } m_proc->setEnvironment( "PASSWD", !authInfo.password().isEmpty() ? authInfo.password() : "" ); #else Smb4KSambaOptionsInfo *info = optionsHandler()->findItem( "//"+m_priv->host()+"/"+m_priv->share() ); int port = info && info->port() != -1 ? info->port() : Smb4KSettings::remotePort(); command.append( Smb4KSettings::alwaysUseSuperUser() ? // FIXME: Check if suid program is installed TQString( "%1 smb4k_mount " ).arg( suid_program ) : "smb4k_mount " ); command.append( optionsHandler()->mountOptions( TQString( "//%1/%2" ).arg( m_priv->host(), m_priv->share() ) ) ); command.append( !m_priv->workgroup().stripWhiteSpace().isEmpty() ? TQString( " -W '%1'" ).arg( m_priv->workgroup() ) : "" ); command.append( !m_priv->ip().stripWhiteSpace().isEmpty() ? TQString( " -I %1" ).arg( m_priv->ip() ) : "" ); command.append( " -N" ); command.append( " -- " ); command.append( TQString( "//%1@'%2':%3/'%4' '%5'" ).arg( !authInfo.user().isEmpty() ? authInfo.user() : "guest" ) .arg( m_priv->host() ) .arg( port ) .arg( m_priv->share(), m_priv->path() ) ); #endif // Start the mount process: *m_proc << command; startProcess( Mount ); } /**************************************************************************** Unmount a share. (Public part) ****************************************************************************/ void Smb4KMounter::unmountShare( Smb4KShare *share, bool force, bool noMessage ) { // Do *not* change share->canonicalPath(). It is necessary for the // checks below to work. m_queue.enqueue( new TQString( TQString( "%1:%2:%3:%4" ).arg( Unmount ) .arg( share->canonicalPath().data() ) .arg( force, noMessage ) ) ); } /*************************************************************************** Unmount a share. (Private part) ***************************************************************************/ void Smb4KMounter::unmount( const TQString &mountpoint, bool force, bool noMessage ) { // First let's see if all requirements are fullfilled: if ( force ) { // Check that the user enabled the "Force Unmounting" ability: if ( !Smb4KSettings::useForceUnmount() ) { Smb4KError::error( ERROR_FEATURE_NOT_ENABLED ); m_working = false; emit state( MOUNTER_STOP ); return; } } // Compose the unmount command: if ( !mountpoint.stripWhiteSpace().isEmpty() ) { bool execute = false; TQString path = mountpoint; m_priv->setPath( path.replace( '\044', "\044" ) ); TQString suid_program, command; if ( Smb4KSettings::useForceUnmount() || Smb4KSettings::alwaysUseSuperUser() ) { switch ( Smb4KSettings::superUserProgram() ) { case Smb4KSettings::EnumSuperUserProgram::Sudo: { suid_program = Smb4KSettings::sudo(); break; } case Smb4KSettings::EnumSuperUserProgram::Super: { suid_program = Smb4KSettings::super(); break; } default: { // FIXME: Throw an error? return; } } } Smb4KShare *share = findShareByPath( mountpoint ); if ( share ) { if ( !share->isForeign() ) { if ( force ) { if ( KMessageBox::questionYesNo( 0, i18n( "Do you really want to force the unmounting of this share?" ), TQString(), KStdGuiItem::yes(), KStdGuiItem::no(), "Dont Ask Forced", KMessageBox::Notify ) == KMessageBox::Yes ) { #ifdef __linux__ command.append( TQString( "%1 smb4k_umount -s -l " ).arg( suid_program ) ); #else #ifdef __FreeBSD__ command.append( TQString( "%1 smb4k_umount " ).arg( suid_program ) ); #else command.append( TQString( "%1 smb4k_umount -s " ).arg( suid_program ) ); #endif #endif execute = true; } else { m_working = false; emit state( MOUNTER_STOP ); return; } } else { if ( !Smb4KSettings::alwaysUseSuperUser() ) { #ifndef __FreeBSD__ command.append( "smb4k_umount -n " ); #else command.append( "smb4k_umount " ); #endif } else { #ifndef __FreeBSD__ command.append( TQString( "%1 smb4k_umount -s " ).arg( suid_program ) ); #else command.append( TQString( "%1 smb4k_umount " ).arg( suid_program ) ); #endif } } } else { if ( Smb4KSettings::unmountForeignShares() ) { if ( force ) { if ( KMessageBox::questionYesNo( 0, i18n( "Do you really want to force the unmounting of this share?" ), TQString(), KStdGuiItem::yes(), KStdGuiItem::no(), "Dont Ask Forced", KMessageBox::Notify ) == KMessageBox::Yes ) { #ifdef __linux__ command.append( TQString( "%1 smb4k_umount -s -l " ).arg( suid_program ) ); #else #ifdef __FreeBSD__ command.append( TQString( "%1 smb4k_umount " ).arg( suid_program ) ); #else command.append( TQString( "%1 smb4k_umount -s " ).arg( suid_program ) ); #endif #endif execute = true; } else { m_working = false; emit state( MOUNTER_STOP ); return; } } else { if ( !Smb4KSettings::alwaysUseSuperUser() ) { #ifndef __FreeBSD__ command.append( "smb4k_umount -n " ); #else command.append( "smb4k_umount " ); #endif } else { #ifndef __FreeBSD__ command.append( TQString( "%1 smb4k_umount -s " ).arg( suid_program ) ); #else command.append( TQString( "%1 smb4k_umount " ).arg( suid_program ) ); #endif } } } else { if ( !noMessage ) { Smb4KError::error( ERROR_UNMOUNTING_NOT_ALLOWED ); } m_working = false; emit state( MOUNTER_STOP ); return; } } #ifndef __FreeBSD__ command.append( TQString( "-t %1 " ).arg( share->filesystem() ) ); #endif command.append( TQString( "'%1'" ).arg( m_priv->path() ) ); if ( force && !execute ) { return; } emit aboutToUnmount( mountpoint ); *m_proc << command; startProcess( Unmount ); } else { // FIXME: Throw an error? return; } } else { Smb4KError::error( ERROR_MOUNTPOINT_EMPTY ); m_working = false; emit state( MOUNTER_STOP ); return; } } /*************************************************************************** Unmounts all shares at once. (Public part) ***************************************************************************/ void Smb4KMounter::unmountAllShares() { m_queue.enqueue( new TQString( TQString( "%1" ).arg( UnmountAll ) ) ); } /*************************************************************************** Unmounts all shares at once. ***************************************************************************/ void Smb4KMounter::unmountAll() { for ( TQValueListIterator it = m_mounted_shares.begin(); it != m_mounted_shares.end(); ++it ) { unmountShare( *it, false, true ); } m_working = false; } /*************************************************************************** Starts any process. ***************************************************************************/ void Smb4KMounter::startProcess( int state ) { m_buffer = TQString(); m_state = state; if ( m_state != Import ) { TQApplication::setOverrideCursor( waitCursor ); } m_proc->start( TDEProcess::NotifyOnExit, TDEProcess::AllOutput ); } /*************************************************************************** Ends any process. This functions tells the mounter what to do afterwards. ***************************************************************************/ void Smb4KMounter::endProcess() { switch ( m_state ) { case Mount: processMount(); break; case Unmount: processUnmount(); break; default: break; } m_state = Idle; m_priv->clearData(); TQApplication::restoreOverrideCursor(); m_proc->clearArguments(); m_working = false; emit state( MOUNTER_STOP ); } /*************************************************************************** Process mounts. ***************************************************************************/ void Smb4KMounter::processMount() { Smb4KShare *share = NULL; #ifndef __FreeBSD__ if ( m_proc->normalExit() ) { if ( m_buffer.contains( "smb4k_mount:", true ) == 0 && m_buffer.contains( "failed", true ) == 0 && m_buffer.contains( "ERR", true ) == 0 && m_buffer.contains( "/bin/sh:" ) == 0 && m_buffer.contains( "mount:", true ) == 0 && m_buffer.contains( "smbmnt" ) == 0 && m_buffer.contains( m_priv->path() ) == 0 && m_buffer.contains( "mount error" ) == 0 && m_buffer.contains( "bad user name" ) == 0 && m_buffer.contains( "bad group name" ) == 0 ) { TQString name = TQString( "//%1/%2" ).arg( m_priv->host() ).arg( m_priv->share() ); // Check file system #if !defined(__sun) struct statfs filesystem; #else struct statvfs filesystem; #endif #if !defined(__sun) && !defined(__irix__) if ( statfs( m_priv->path(), &filesystem ) == -1 ) #elif defined(__irix__) if ( statfs( m_priv->path(), &filesystem, sizeof( filesystem ), 0 ) == -1 ) #else if ( statvfs( m_priv->path(), &filesystem ) == -1 ) #endif { // The query failed. Go with the file system already defined in m_priv. if ( TQString::compare( m_priv->filesystem(), "smbfs" ) == 0 ) { share = new Smb4KShare( name, m_priv->path(), m_priv->filesystem(), (int)getuid(), (int)getgid() ); m_mounted_shares.append( share ); } else if ( TQString::compare( m_priv->filesystem(), "cifs" ) == 0 ) { // The user name will be send if no login was specified. TQString cifs_login = !m_priv->cifsLogin().isEmpty() ? m_priv->cifsLogin() : getpwuid( getuid() )->pw_name; share = new Smb4KShare( name, m_priv->path(), m_priv->filesystem(), cifs_login, false ); m_mounted_shares.append( share ); } } else { #if !defined(__FreeBSD__) && !defined(__sun) && !defined(__irix__) if ( (uint)filesystem.f_type == 0xFF534D42 /* CIFS */) { // The user name will be send if no login was specified. TQString cifs_login = !m_priv->cifsLogin().isEmpty() ? m_priv->cifsLogin() : getpwuid( getuid() )->pw_name; share = new Smb4KShare( name, m_priv->path(), "cifs", cifs_login, false ); m_mounted_shares.append( share ); } else if ( (uint)filesystem.f_type == 0x517B /* SMBFS */) { share = new Smb4KShare( name, m_priv->path(), "smbfs", (int)getuid(), (int)getgid() ); m_mounted_shares.append( share ); } #elif defined(__sun) if ( (uint)filesystem.f_basetype == 0xFF534D42 /* CIFS */) { // The user name will be send if no login was specified. TQString cifs_login = !m_priv->cifsLogin().isEmpty() ? m_priv->cifsLogin() : getpwuid( getuid() )->pw_name; share = new Smb4KShare( name, m_priv->path(), "cifs", cifs_login, false ); m_mounted_shares.append( share ); } else if ( (uint)filesystem.f_basetype == 0x517B /* SMBFS */) { share = new Smb4KShare( name, m_priv->path(), "smbfs", (int)getuid(), (int)getgid() ); m_mounted_shares.append( share ); } #elif defined(__irix__) if ( (uint)filesystem.f_fstyp == 0xFF534D42 /* CIFS */) { // The user name will be send if no login was specified. TQString cifs_login = !m_priv->cifsLogin().isEmpty() ? m_priv->cifsLogin() : getpwuid( getuid() )->pw_name; share = new Smb4KShare( name, m_priv->path(), "cifs", cifs_login, false ); m_mounted_shares.append( share ); } else if ( (uint)filesystem.f_basetype == 0x517B && !strncmp( fs, "smbfs", strlen( fs )+1 ) ) { share = new Smb4KShare( name, m_priv->path(), "smbfs", (int)getuid(), (int)getgid() ); m_mounted_shares.append( share ); } #endif else { // Error... We don't create a share. } } if ( share ) { // Check that the share is accessible: checkAccessibility( share ); emit mountedShare( m_priv->path() ); } } else { if ( m_buffer.contains( "ERRbadpw" ) != 0 || m_buffer.contains( "ERRnoaccess" ) != 0 || m_buffer.contains( "mount error 13 = Permission denied" ) != 0 ) { int state = Smb4KPasswordHandler::None; if ( m_buffer.contains( "ERRbadpw" ) != 0 ) { state = Smb4KPasswordHandler::BadPassword; } else if ( m_buffer.contains( "ERRnoaccess" ) != 0 ) { state = Smb4KPasswordHandler::AccessDenied; } else if ( m_buffer.contains( "mount error 13 = Permission denied" ) != 0 ) { state = Smb4KPasswordHandler::PermDenied; } // If the user supplied auth information, we will retry mounting. if ( passwordHandler()->askpass( m_priv->workgroup(), m_priv->host(), m_priv->share(), state ) ) { mountShare( m_priv->workgroup(), m_priv->host(), m_priv->ip(), m_priv->share() ); } } else if ( m_buffer.contains( "ERRnosuchshare" ) != 0 && m_priv->share().contains( "_" ) != 0 ) { TQString share_string = static_cast( m_priv->share() ).replace( "_", " " ); mountShare( m_priv->workgroup(), m_priv->host(), m_priv->ip(), share_string ); } else { TQString name = TQString( "//%1/%2" ).arg( m_priv->host() ).arg( m_priv->share() ); Smb4KError::error( ERROR_MOUNTING_SHARE, name, m_buffer ); } } } #else if ( m_proc->normalExit() ) { if ( m_buffer.contains( "smb4k_mount:", true ) == 0 && m_buffer.contains( "syserr =", true ) == 0 && /* To make sure we catch all errors, also check for the following strings. Maybe we can remove them?? */ m_buffer.contains( "Authentication error", true ) == 0 && m_buffer.contains( "Connection refused", true ) == 0 && m_buffer.contains( "Operation not permitted", true ) == 0 ) { import(); // FIXME: *cough* What is this for??? Smb4KAuthInfo authInfo( m_priv->workgroup(), m_priv->host(), m_priv->share() ); (void) passwordHandler()->readAuth( &authInfo ); TQString name = TQString( "//%1@%2/%3" ).arg( authInfo.user().upper(), m_priv->host().upper(), m_priv->share().upper() ); share = new Smb4KShare( name, m_priv->path(), m_priv->filesystem(), (int)getuid(), (int)getgid() ); m_mounted_shares.append( share ); // Check that the share is accessible: checkAccessibility( share ); emit mountedShare( m_priv->path() ); } else { if ( m_buffer.contains( "Authentication error" ) != 0 ) { // If the user supplied auth information, we will retry mounting. if ( passwordHandler()->askpass( m_priv->workgroup(), m_priv->host(), m_priv->share(), Smb4KPasswordHandler::AuthError ) ) { mountShare( m_priv->workgroup(), m_priv->host(), m_priv->ip() , m_priv->share() ); } } else { Smb4KAuthInfo authInfo( m_priv->workgroup(), m_priv->host(), m_priv->share() ); (void) passwordHandler()->readAuth( &authInfo ); TQString name = TQString( "//%1@%2/%3" ).arg( authInfo.user().upper(), m_priv->host().upper(), m_priv->share().upper() ); Smb4KError::error( ERROR_MOUNTING_SHARE, name, m_buffer ); } } } #endif emit updated(); } /*************************************************************************** Process unmounts. ***************************************************************************/ void Smb4KMounter::processUnmount() { // Get the share: Smb4KShare *share = findShareByPath( m_priv->path() ); if ( m_proc->normalExit() ) { if ( m_buffer.isEmpty() ) { if ( tqstrncmp( share->canonicalPath(), TQDir( Smb4KSettings::mountPrefix() ).canonicalPath().local8Bit(), TQDir( Smb4KSettings::mountPrefix() ).canonicalPath().local8Bit().length() ) == 0 ) { TQDir dir( share->canonicalPath() ); if ( dir.rmdir( dir.canonicalPath(), true ) ) { dir.cdUp(); dir.rmdir( dir.canonicalPath(), true ); } } m_mounted_shares.remove(share); } else { // If the user's computer is configured by a DHCP server, under // rare circumstances it might occur that sudo reports an error, // because it is not able to resolve the host. This error message // will be removed, because it does not affect the unmounting: if ( m_buffer.contains( "sudo: unable to resolve host", true ) != 0 ) { size_t hostnamelen = 255; char *hostname = new char[hostnamelen]; if ( gethostname( hostname, hostnamelen ) == -1 ) { int error_number = errno; Smb4KError::error( ERROR_GETTING_HOSTNAME, TQString(), strerror( error_number ) ); } else { TQString str = TQString( "sudo: unable to resolve host %1\n" ).arg( hostname ); m_buffer.remove( str, false /* case insensitive */ ); if ( !m_buffer.isEmpty() ) { Smb4KError::error( ERROR_UNMOUNTING_SHARE, share->name(), m_buffer ); } else { if ( tqstrncmp( share->canonicalPath(), TQDir( Smb4KSettings::mountPrefix() ).canonicalPath().local8Bit(), TQDir( Smb4KSettings::mountPrefix() ).canonicalPath().local8Bit().length() ) == 0 ) { TQDir dir( share->canonicalPath() ); if ( dir.rmdir( dir.canonicalPath(), true ) ) { dir.cdUp(); dir.rmdir( dir.canonicalPath(), true ); } } m_mounted_shares.remove(share); } } delete [] hostname; } else { Smb4KError::error( ERROR_UNMOUNTING_SHARE, share->name(), m_buffer ); } } } emit updated(); } /*************************************************************************** Check if a share is already mounted ***************************************************************************/ bool Smb4KMounter::isMounted( const TQString &name, bool userOnly ) { TQValueList list = findShareByName( name ); bool mounted = false; if ( !list.isEmpty() && userOnly ) { for ( TQValueList::ConstIterator it = list.begin(); it != list.end(); ++it ) { if ( !(*it).isForeign() ) { mounted = true; break; } else { continue; } } } else { mounted = !list.isEmpty(); } return mounted; } /*************************************************************************** Find a share in the list with its path ***************************************************************************/ Smb4KShare* Smb4KMounter::findShareByPath( const TQString &path ) { if ( path.isEmpty() || m_mounted_shares.isEmpty() ) { return NULL; } Smb4KShare *share = NULL; for ( TQValueListIterator it = m_mounted_shares.begin(); it != m_mounted_shares.end(); ++it ) { if( TQString::compare( path.upper(), TQString(TQString::fromLocal8Bit( (*it)->path(), -1 )).upper() ) == 0 || TQString::compare( path.upper(), TQString(TQString::fromLocal8Bit( (*it)->canonicalPath(), -1 )).upper() ) == 0 ) { share = *it; break; } } return share; } /*************************************************************************** Find the list of mounts of a share ***************************************************************************/ TQValueList Smb4KMounter::findShareByName( const TQString &name ) { TQValueList list; if ( name.isEmpty() || m_mounted_shares.isEmpty() ) { return list; // is empty } TQString n = name; for ( TQValueListIterator it = m_mounted_shares.begin(); it != m_mounted_shares.end(); ++it ) { if( TQString::compare( (*it)->name().upper(), name.upper() ) == 0 || TQString::compare( (*it)->name().upper(), n.replace( " ", "_" ).upper() ) == 0 ) { list.append( *(*it) ); continue; } else { continue; } } return list; } /*************************************************************************** Returns a list of mount points that belong to broken shares ***************************************************************************/ const TQValueList Smb4KMounter::getBrokenShares() { TQValueList broken_shares; for ( TQValueListIterator it = m_mounted_shares.begin(); it != m_mounted_shares.end(); ++it ) { if ( (*it)->isBroken() ) { broken_shares.append( *it ); continue; } else { continue; } } return broken_shares; } void Smb4KMounter::prepareForShutdown() { slotShutdown(); } void Smb4KMounter::checkAccessibility( Smb4KShare *share ) { if ( share ) { m_priv->thread.setMountpoint( share->path() ); m_priv->thread.start(); m_priv->thread.wait( THREAD_WAITING_TIME ); m_priv->thread.terminate(); m_priv->thread.wait(); share->setBroken( m_priv->thread.isBroken() ); share->setTotalDiskSpace( m_priv->thread.totalDiskSpace() ); share->setFreeDiskSpace( m_priv->thread.freeDiskSpace() ); } else { // FIXME: Should we throw an error here? } } void Smb4KMounter::timerEvent( TQTimerEvent * ) { if ( !m_working && !m_queue.isEmpty() ) { // Tell the mounter, that it is busy. m_working = true; TQString *item = m_queue.dequeue(); int todo = item->section( ":", 0, 0 ).toInt(); switch ( todo ) { case Remount: { remount(); break; } case Import: { import(); break; } case Mount: { emit state( MOUNTER_MOUNTING ); mount( item->section( ":", 1, 1 ), item->section( ":", 2, 2 ), item->section( ":", 3, 3 ), item->section( ":", 4, 4 ) ); break; } case Unmount: { emit state( MOUNTER_UNMOUNTING ); unmount( item->section( ":", 1, 1 ), (bool)item->section( ":", 2, 2 ).toInt() /* force */, (bool)item->section( ":", 3, 3 ).toInt() /* noMessage */); break; } case UnmountAll: { unmountAll(); break; } default: { break; } } delete item; } m_priv->timerTicks++; if ( m_priv->timerTicks * timerInterval() >= Smb4KSettings::checkInterval() /* msec */ && (!m_working || m_queue.isEmpty()) ) { m_queue.enqueue( new TQString( TQString( "%1:" ).arg( Import ) ) ); m_priv->timerTicks = 0; } } ///////////////////////////////////////////////////////////////////////////// // TQT_SLOT IMPLEMENTATIONS ///////////////////////////////////////////////////////////////////////////// void Smb4KMounter::slotProcessExited( TDEProcess * ) { endProcess(); } void Smb4KMounter::slotReceivedStdout( TDEProcess *, char *buf, int len ) { m_buffer.append( TQString::fromLocal8Bit( buf, len ) ); } void Smb4KMounter::slotReceivedStderr( TDEProcess *, char *buf, int len ) { m_buffer.append( TQString::fromLocal8Bit( buf, len ) ); } void Smb4KMounter::slotShutdown() { // Abort any action: abort(); // Prepare for shutdown: if ( Smb4KSettings::remountShares() && !m_mounted_shares.isEmpty() ) { for ( TQValueList::ConstIterator it = m_mounted_shares.begin(); it != m_mounted_shares.end(); ++it ) { optionsHandler()->remount( *it, !(*it)->isForeign() ); } } optionsHandler()->sync(); TQDir dir; dir.cd( Smb4KSettings::mountPrefix() ); TQStringList dirs = dir.entryList( TQDir::Dirs, TQDir::DefaultSort ); TQValueList broken_shares = getBrokenShares(); for ( TQStringList::ConstIterator it = dirs.begin(); it != dirs.end(); ++it ) { if ( TQString::compare( *it, "." ) != 0 && TQString::compare( *it, ".." ) != 0 ) { bool broken = false; for ( TQValueListIterator bs = broken_shares.begin(); bs != broken_shares.end(); ++bs ) { if ( tqstrncmp( (*bs)->path(), Smb4KSettings::mountPrefix()+*it, (Smb4KSettings::mountPrefix()+*it).length() ) == 0 || tqstrncmp( (*bs)->canonicalPath(), Smb4KSettings::mountPrefix()+*it, (Smb4KSettings::mountPrefix()+*it).length() ) == 0 ) { broken = true; break; } else { continue; } } if ( !broken ) { dir.cd( *it ); TQStringList subdirs = dir.entryList( TQDir::Dirs, TQDir::DefaultSort ); for ( TQStringList::ConstIterator i = subdirs.begin(); i != subdirs.end(); ++i ) { if ( TQString::compare( *i, "." ) != 0 && TQString::compare( *i, ".." ) != 0 ) { dir.rmdir( *i ); } } dir.cdUp(); dir.rmdir( *it ); } } } broken_shares.clear(); if ( Smb4KSettings::unmountSharesOnExit() ) { TQString suid_program, command; switch( Smb4KSettings::superUserProgram() ) { case Smb4KSettings::EnumSuperUserProgram::Sudo: { suid_program = Smb4KSettings::sudo(); break; } case Smb4KSettings::EnumSuperUserProgram::Super: { suid_program = Smb4KSettings::super(); break; } default: { // FIXME: Throw an error? return; } } TDEProcess proc; proc.setUseShell( true ); proc.detach(); for ( TQValueListIterator it = m_mounted_shares.begin(); it != m_mounted_shares.end(); ++it ) { if ( !(*it)->isForeign() ) { if ( Smb4KSettings::alwaysUseSuperUser() ) { #ifndef __FreeBSD__ command.append( TQString( "%1 smb4k_umount -s -t %2 " ).arg( suid_program ).arg( (*it)->filesystem() ) ); #else command.append( TQString( "%1 smb4k_umount " ).arg( suid_program ) ); #endif command.append( TDEProcess::quote( (*it)->path() ) ); command.append( " ; " ); } else { #ifndef __FreeBSD__ command.append( TQString( "smb4k_umount -n -t %1 " ).arg( (*it)->filesystem() ) ); #else command.append( "smb4k_umount " ); #endif command.append( TDEProcess::quote( (*it)->path() ) ); command.append( " ; " ); } dir.setPath( (*it)->canonicalPath() ); #ifndef __FreeBSD__ command.append( "rmdir --ignore-fail-on-non-empty " ); command.append( TDEProcess::quote( dir.canonicalPath() ) ); command.append( " ; " ); command.append( "rmdir --ignore-fail-on-non-empty " ); dir.cdUp(); command.append( TDEProcess::quote( dir.canonicalPath() ) ); command.append( " ; " ); #else command.append( "rmdir " ); command.append( TDEProcess::quote( dir.canonicalPath() ) ); command.append( " ; " ); command.append( "rmdir " ); dir.cdUp(); command.append( TDEProcess::quote( dir.canonicalPath() ) ); command.append( " ; " ); #endif } else { continue; } } command.truncate( command.length() - 2 ); proc << command; proc.start( TDEProcess::DontCare, TDEProcess::NoCommunication ); } } #include "smb4kmounter.moc"