File indexing completed on 2022-11-29 20:24:03

0001 /*
0002     SPDX-FileCopyrightText: 1998 Michael Kropfberger <michael.kropfberger@gmx.net>
0003     SPDX-License-Identifier: GPL-2.0-or-later
0004 */
0005 
0006 #include "disks.h"
0007 
0008 #include "kdfprivate_debug.h"
0009 
0010 #include <KLocalizedString>
0011 #include <KProcess>
0012 
0013 #include <QFileInfo>
0014 #include <QDir>
0015 
0016 #include <unistd.h>
0017 #include <sys/types.h>
0018 
0019 /****************************************************/
0020 /********************* DiskEntry ********************/
0021 /****************************************************/
0022 
0023 /**
0024   * Constructor
0025 **/
0026 void DiskEntry::init(const QString &name)
0027 {
0028     setObjectName( name );
0029     device.clear();
0030     type.clear();
0031     mountedOn.clear();
0032     options.clear();
0033     size=0;
0034     used=0;
0035     avail=0;
0036     isMounted=false;
0037     mntcmd.clear();
0038     umntcmd.clear();
0039     iconSetByUser=false;
0040     icoName.clear();
0041 
0042 
0043     // BackgroundProcesses ****************************************
0044 
0045     sysProc = new KProcess();
0046     Q_CHECK_PTR(sysProc);
0047     sysProc->setOutputChannelMode( KProcess::MergedChannels );
0048     connect( sysProc, &QProcess::readyReadStandardError,
0049              this, &DiskEntry::receivedSysStdErrOut );
0050     connect( sysProc, &QProcess::readyReadStandardOutput,
0051              this, &DiskEntry::receivedSysStdErrOut );
0052     readingSysStdErrOut=false;
0053 
0054 
0055 }
0056 
0057 DiskEntry::DiskEntry(QObject *parent, const QString &name)
0058         : QObject (parent)
0059 {
0060     init(name);
0061 }
0062 
0063 DiskEntry::DiskEntry(const QString & deviceName, QObject *parent, const QString &name)
0064         : QObject (parent)
0065 {
0066     init(name);
0067 
0068     setDeviceName(deviceName);
0069 }
0070 DiskEntry::~DiskEntry()
0071 {
0072     disconnect(this);
0073     if ( sysProc->state() == QProcess::Running )
0074     {
0075         sysProc->terminate();
0076         sysProc->waitForFinished(-1);
0077     }
0078     delete sysProc;
0079 }
0080 
0081 int DiskEntry::toggleMount()
0082 {
0083     if (!mounted())
0084         return mount();
0085     else
0086         return umount();
0087 }
0088 
0089 int DiskEntry::mount()
0090 {
0091     QString cmdS=mntcmd;
0092     if ( cmdS.isEmpty() )
0093     { // generate default mount cmd
0094         if ( getuid()!=0 ) // user mountable
0095         {
0096             cmdS = QStringLiteral( "mount %d" );
0097         }
0098         else  // root mounts with all params/options
0099         {
0100             // FreeBSD's mount(8) is picky: -o _must_ go before
0101             // the device and mountpoint.
0102             cmdS = QStringLiteral( "mount -t%t -o%o %d %m" );
0103         }
0104     }
0105 
0106     cmdS.replace( QLatin1String( "%d" ), deviceName() );
0107     cmdS.replace( QLatin1String( "%m" ), mountPoint() );
0108     cmdS.replace( QLatin1String( "%t" ), fsType() );
0109     cmdS.replace( QLatin1String( "%o" ), mountOptions() );
0110 
0111     qCDebug(KDF) << "mount-cmd: [" << cmdS << "]";
0112     int e = sysCall( cmdS );
0113     if (!e)
0114         setMounted( true );
0115     qCDebug(KDF) << "mount-cmd: e=" << e;
0116     return e;
0117 }
0118 
0119 int DiskEntry::umount()
0120 {
0121     qCDebug(KDF) << "umounting";
0122     QString cmdS = umntcmd;
0123     if ( cmdS.isEmpty() ) // generate default umount cmd
0124         cmdS = QStringLiteral( "umount %d" );
0125 
0126     cmdS.replace( QLatin1String( "%d" ), deviceName() );
0127     cmdS.replace( QLatin1String( "%m" ), mountPoint() );
0128 
0129     qCDebug(KDF) << "umount-cmd: [" << cmdS << "]";
0130     int e = sysCall( cmdS );
0131     if ( !e )
0132         setMounted( false );
0133     qCDebug(KDF) << "umount-cmd: e=" << e;
0134 
0135     return e;
0136 }
0137 
0138 int DiskEntry::remount()
0139 {
0140     if ( mntcmd.isEmpty() && umntcmd.isEmpty() // default mount/umount commands
0141             && ( getuid()==0) ) // you are root
0142     {
0143         QString oldOpt = options;
0144         if (options.isEmpty())
0145             options = QStringLiteral( "remount" );
0146         else
0147             options += QLatin1String( ",remount" );
0148 
0149         int e = mount();
0150         options = oldOpt;
0151         return e;
0152     } else
0153     {
0154         if ( int e=umount() )
0155             return mount();
0156         else
0157             return e;
0158     }
0159 }
0160 
0161 void DiskEntry::setMountCommand(const QString & mnt)
0162 {
0163     mntcmd=mnt;
0164 }
0165 
0166 void DiskEntry::setUmountCommand(const QString & umnt)
0167 {
0168     umntcmd=umnt;
0169 }
0170 
0171 void DiskEntry::setIconName(const QString & iconName)
0172 {
0173     iconSetByUser=true;
0174     icoName=iconName;
0175     if ( icoName.right(6) == QLatin1String( "_mount" ) )
0176         icoName.chop(6);
0177     else if ( icoName.right(8) == QLatin1String( "_unmount" ) )
0178         icoName.chop(8);
0179 
0180     Q_EMIT iconNameChanged();
0181 }
0182 
0183 void DiskEntry::setIconToDefault()
0184 {
0185     iconSetByUser = false;
0186     icoName.clear();
0187 
0188 }
0189 
0190 QString DiskEntry::iconName()
0191 {
0192     if (iconSetByUser)
0193         return icoName;
0194     else
0195         return guessIconName();
0196 }
0197 
0198 //TODO: Need porting to solid
0199 QString DiskEntry::guessIconName()
0200 {
0201     QString iconName;
0202 
0203     /*
0204     //List Solid Devices
0205     foreach (const Solid::Device &device, Solid::Device::listFromType(Solid::DeviceInterface::StorageVolume))
0206       {
0207           qCDebug(KDF) << device.udi().toLatin1().constData() << device.vendor() << device.product() << device.icon();
0208       }
0209     Solid::Device * device = new Solid::Device(deviceName());
0210     qCDebug(KDF) << "guess" << deviceName() << device->icon();
0211     delete device;
0212     */
0213     // try to be intelligent
0214     if (mountPoint().contains(QLatin1String( "cdrom" ),Qt::CaseInsensitive))
0215         iconName+=QLatin1String( "media-optical" );
0216     else if (deviceName().contains(QLatin1String( "cdrom" ),Qt::CaseInsensitive))
0217         iconName+=QLatin1String( "media-optical" );
0218     else if (mountPoint().contains(QLatin1String( "writer" ),Qt::CaseInsensitive))
0219         iconName+=QLatin1String( "media-optical-recordable" );
0220     else if (deviceName().contains(QLatin1String( "writer" ),Qt::CaseInsensitive))
0221         iconName+=QLatin1String( "media-optical-recordable" );
0222     else if (mountPoint().contains(QLatin1String( "mo" ),Qt::CaseInsensitive))
0223         iconName+=QLatin1String( "mo" ); //TODO
0224     else if (deviceName().contains(QLatin1String( "mo" ),Qt::CaseInsensitive))
0225         iconName+=QLatin1String( "mo" ); //TODO
0226     else if (deviceName().contains(QLatin1String( "fd" ),Qt::CaseInsensitive))
0227     {
0228         if (deviceName().contains(QLatin1String( "360" ),Qt::CaseInsensitive))
0229             iconName+=QLatin1String( "5floppy" ); //TODO
0230         if (deviceName().contains(QLatin1String( "1200" ),Qt::CaseInsensitive))
0231             iconName+=QLatin1String( "5floppy" ); //TODO
0232         else
0233             iconName+=QLatin1String( "media-floppy" );
0234     }
0235     else if (mountPoint().contains(QLatin1String( "floppy" ),Qt::CaseInsensitive))
0236         iconName+=QLatin1String( "media-floppy" );
0237     else if (mountPoint().contains(QLatin1String( "zip" ),Qt::CaseInsensitive))
0238         iconName+=QLatin1String( "zip" ); //TODO
0239     else if (fsType().contains(QLatin1String( "nfs" ),Qt::CaseInsensitive))
0240         iconName+=QLatin1String( "nfs" ); //TODO
0241     else
0242         iconName+=QLatin1String( "drive-harddisk" );
0243     ///mounted() ? iconName+="_mount" : iconName+="_unmount";
0244     //    if ( !mountOptions().contains("user",Qt::CaseInsensitive) )
0245     //      iconName.prepend("root_"); // special root icon, normal user can't mount
0246 
0247     //debug("device %s is %s",deviceName().latin1(),iconName.latin1());
0248 
0249     //Q_EMIT iconNameChanged();
0250     return iconName;
0251 }
0252 
0253 
0254 /***************************************************************************
0255   * starts a command on the underlying system via /bin/sh
0256 **/
0257 int DiskEntry::sysCall(QString & completeCommand)
0258 {
0259     if (readingSysStdErrOut || sysProc->state() == QProcess::Running )
0260         return -1;
0261 
0262     sysStringErrOut=i18n("Called: %1\n\n", completeCommand); // put the called command on ErrOut
0263     sysProc->clearProgram();
0264 
0265     //Split command and arguments to use the new API, otherwise it doesn't work
0266     QTextStream tS(&completeCommand);
0267 
0268     QString command;
0269     tS >> command;
0270 
0271     QString tmp;
0272     QStringList args;
0273     while( !tS.atEnd() )
0274     {
0275         tS >> tmp;
0276         args << tmp;
0277     }
0278 
0279     sysProc->setProgram(command, args);
0280     sysProc->start();
0281 
0282     if ( !sysProc->waitForStarted(-1) )
0283         qCCritical(KDF) << i18n("could not execute %1", command) ;
0284 
0285     sysProc->waitForFinished(-1);
0286 
0287     if (sysProc->exitCode()!=0)
0288         Q_EMIT sysCallError(this, sysProc->exitStatus());
0289 
0290     return (sysProc->exitCode());
0291 }
0292 
0293 
0294 /***************************************************************************
0295   * is called, when the Sys-command writes on StdOut or StdErr
0296 **/
0297 void DiskEntry::receivedSysStdErrOut()
0298 {
0299     QString stdOut = QString::fromLocal8Bit( sysProc->readAllStandardOutput() );
0300     QString stdErr = QString::fromLocal8Bit( sysProc->readAllStandardError() );
0301 
0302     sysStringErrOut.append( stdOut );
0303     sysStringErrOut.append( stdErr );
0304 }
0305 
0306 int DiskEntry::percentFull() const
0307 {
0308     if (size != 0)
0309     {
0310         return 100 - qRound((qreal(avail) / qreal(size)) * 100);
0311     }
0312     else
0313     {
0314         return -1;
0315     }
0316 }
0317 
0318 void DiskEntry::setDeviceName(const QString & deviceName)
0319 {
0320     device=deviceName;
0321     Q_EMIT deviceNameChanged();
0322 }
0323 
0324 QString DiskEntry::deviceRealName() const
0325 {
0326     QFileInfo inf( device );
0327     QDir dir( inf.absolutePath() );
0328     QString relPath = inf.fileName();
0329     if ( inf.isSymLink() )
0330     {
0331         QString link = inf.symLinkTarget();
0332         if ( link.startsWith( QLatin1Char( '/' ) ) )
0333             return link;
0334         relPath = link;
0335     }
0336     return dir.canonicalPath() + QLatin1Char( '/' ) + relPath;
0337 }
0338 
0339 void DiskEntry::setMountPoint(const QString & mountPoint)
0340 {
0341     mountedOn=mountPoint;
0342     Q_EMIT mountPointChanged();
0343 }
0344 
0345 QString DiskEntry::realMountPoint() const
0346 {
0347     QDir dir( mountedOn );
0348     return dir.canonicalPath();
0349 }
0350 
0351 void DiskEntry::setMountOptions(const QString & mountOptions)
0352 {
0353     options=mountOptions;
0354     Q_EMIT mountOptionsChanged();
0355 }
0356 
0357 void DiskEntry::setFsType(const QString & fsType)
0358 {
0359     type=fsType;
0360     Q_EMIT fsTypeChanged();
0361 }
0362 
0363 void DiskEntry::setMounted(bool nowMounted)
0364 {
0365     isMounted=nowMounted;
0366     Q_EMIT mountedChanged();
0367 }
0368 
0369 void DiskEntry::setKBSize(qulonglong kb_size)
0370 {
0371     size=kb_size;
0372     Q_EMIT kBSizeChanged();
0373 }
0374 
0375 void DiskEntry::setKBUsed(qulonglong kb_used)
0376 {
0377     used=kb_used;
0378     if ( size < (used+avail) )
0379     {  //adjust kBAvail
0380         qCWarning(KDF) << "device " << device << ": kBAvail(" << avail << ")+*kBUsed(" << used << ") exceeds kBSize(" << size << ")" ;
0381         setKBAvail(size-used);
0382     }
0383     Q_EMIT kBUsedChanged();
0384 }
0385 
0386 void DiskEntry::setKBAvail(qulonglong kb_avail)
0387 {
0388     avail=kb_avail;
0389     if ( size < (used+avail) )
0390     {  //adjust kBUsed
0391         qCWarning(KDF) << "device " << device << ": *kBAvail(" << avail << ")+kBUsed(" << used << ") exceeds kBSize(" << size << ")" ;
0392         setKBUsed(size-avail);
0393     }
0394     Q_EMIT kBAvailChanged();
0395 }
0396 
0397