diff options
Diffstat (limited to 'kdf/disklist.cpp')
-rw-r--r-- | kdf/disklist.cpp | 506 |
1 files changed, 506 insertions, 0 deletions
diff --git a/kdf/disklist.cpp b/kdf/disklist.cpp new file mode 100644 index 0000000..b2718ac --- /dev/null +++ b/kdf/disklist.cpp @@ -0,0 +1,506 @@ +/* + * disklist.cpp + * + * Copyright (c) 1999 Michael Kropfberger <michael.kropfberger@gmx.net> + * + * Requires the Qt widget libraries, available at no cost at + * http://www.troll.no/ + * + * 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. + */ + +#include <config.h> + +#include <math.h> +#include <stdlib.h> +#include <kdebug.h> +#include <kapplication.h> + +#include "disklist.h" + +#define BLANK ' ' +#define DELIMITER '#' +#define FULL_PERCENT 95.0 + +/*************************************************************************** + * constructor +**/ +DiskList::DiskList(QObject *parent, const char *name) + : QObject(parent,name) +{ + kdDebug() << k_funcinfo << endl; + + updatesDisabled = false; + + if (NO_FS_TYPE) { + kdDebug() << "df gives no FS_TYPE" << endl; + } + + disks = new Disks; + disks->setAutoDelete(TRUE); + + // BackgroundProcesses **************************************** + dfProc = new KProcess(); Q_CHECK_PTR(dfProc); + connect( dfProc, SIGNAL(receivedStdout(KProcess *, char *, int) ), + this, SLOT (receivedDFStdErrOut(KProcess *, char *, int)) ); + connect(dfProc,SIGNAL(processExited(KProcess *) ), + this, SLOT(dfDone() ) ); + + readingDFStdErrOut=FALSE; + config = kapp->config(); + loadSettings(); +} + + +/*************************************************************************** + * destructor +**/ +DiskList::~DiskList() +{ + kdDebug() << k_funcinfo << endl; +} + +/** +Updated need to be disabled sometimes to avoid pulling the DiskEntry out from the popupmenu handler +*/ +void DiskList::setUpdatesDisabled(bool disable) +{ + updatesDisabled = disable; +} + +/*************************************************************************** + * saves the KConfig for special mount/umount scripts +**/ +void DiskList::applySettings() +{ + kdDebug() << k_funcinfo << endl; + + QString oldgroup=config->group(); + config->setGroup("DiskList"); + QString key; + DiskEntry *disk; + for (disk=disks->first();disk!=0;disk=disks->next()) { + key.sprintf("Mount%s%s%s%s",SEPARATOR,disk->deviceName().latin1() + ,SEPARATOR,disk->mountPoint().latin1()); + config->writePathEntry(key,disk->mountCommand()); + + key.sprintf("Umount%s%s%s%s",SEPARATOR,disk->deviceName().latin1() + ,SEPARATOR,disk->mountPoint().latin1()); + config->writePathEntry(key,disk->umountCommand()); + + key.sprintf("Icon%s%s%s%s",SEPARATOR,disk->deviceName().latin1() + ,SEPARATOR,disk->mountPoint().latin1()); + config->writePathEntry(key,disk->realIconName()); + } + config->sync(); + config->setGroup(oldgroup); +} + + +/*************************************************************************** + * reads the KConfig for special mount/umount scripts +**/ +void DiskList::loadSettings() +{ + kdDebug() << k_funcinfo << endl; + + config->setGroup("DiskList"); + QString key; + DiskEntry *disk; + for (disk=disks->first();disk!=0;disk=disks->next()) { + key.sprintf("Mount%s%s%s%s",SEPARATOR,disk->deviceName().latin1() + ,SEPARATOR,disk->mountPoint().latin1()); + disk->setMountCommand(config->readPathEntry(key)); + + key.sprintf("Umount%s%s%s%s",SEPARATOR,disk->deviceName().latin1() + ,SEPARATOR,disk->mountPoint().latin1()); + disk->setUmountCommand(config->readPathEntry(key)); + + key.sprintf("Icon%s%s%s%s",SEPARATOR,disk->deviceName().latin1() + ,SEPARATOR,disk->mountPoint().latin1()); + QString icon=config->readPathEntry(key); + if (!icon.isEmpty()) disk->setIconName(icon); + } +} + + +static QString expandEscapes(const QString& s) { +QString rc; + for (unsigned int i = 0; i < s.length(); i++) { + if (s[i] == '\\') { + i++; + switch(s[i]) { + case '\\': // backslash '\' + rc += '\\'; + break; + case '0': // octal 0nn + rc += static_cast<char>(s.mid(i,3).toInt(0, 8)); + i += 2; + break; + default: + // give up and not process anything else because I'm too lazy + // to implement other escapes + rc += '\\'; + rc += s[i]; + break; + } + } else { + rc += s[i]; + } + } +return rc; +} + +/*************************************************************************** + * tries to figure out the possibly mounted fs +**/ +int DiskList::readFSTAB() +{ + kdDebug() << k_funcinfo << endl; + + if (readingDFStdErrOut || dfProc->isRunning()) return -1; + +QFile f(FSTAB); + if ( f.open(IO_ReadOnly) ) { + QTextStream t (&f); + QString s; + DiskEntry *disk; + + //disks->clear(); // ############ + + while (! t.eof()) { + s=t.readLine(); + s=s.simplifyWhiteSpace(); + if ( (!s.isEmpty() ) && (s.find(DELIMITER)!=0) ) { + // not empty or commented out by '#' + // kdDebug() << "GOT: [" << s << "]" << endl; + disk = new DiskEntry();// Q_CHECK_PTR(disk); + disk->setMounted(FALSE); + disk->setDeviceName(expandEscapes(s.left(s.find(BLANK)))); + s=s.remove(0,s.find(BLANK)+1 ); + // kdDebug() << " deviceName: [" << disk->deviceName() << "]" << endl; +#ifdef _OS_SOLARIS_ + //device to fsck + s=s.remove(0,s.find(BLANK)+1 ); +#endif + disk->setMountPoint(expandEscapes(s.left(s.find(BLANK)))); + s=s.remove(0,s.find(BLANK)+1 ); + //kdDebug() << " MountPoint: [" << disk->mountPoint() << "]" << endl; + //kdDebug() << " Icon: [" << disk->iconName() << "]" << endl; + disk->setFsType(s.left(s.find(BLANK)) ); + s=s.remove(0,s.find(BLANK)+1 ); + //kdDebug() << " FS-Type: [" << disk->fsType() << "]" << endl; + disk->setMountOptions(s.left(s.find(BLANK)) ); + s=s.remove(0,s.find(BLANK)+1 ); + //kdDebug() << " Mount-Options: [" << disk->mountOptions() << "]" << endl; + if ( (disk->deviceName() != "none") + && (disk->fsType() != "swap") + && (disk->fsType() != "sysfs") + && (disk->mountPoint() != "/dev/swap") + && (disk->mountPoint() != "/dev/pts") + && (disk->mountPoint() != "/dev/shm") + && (disk->mountPoint().find("/proc") == -1 ) ) + replaceDeviceEntry(disk); + else + delete disk; + + } //if not empty + } //while + f.close(); + } //if f.open + + loadSettings(); //to get the mountCommands + + // kdDebug() << "DiskList::readFSTAB DONE" << endl; + return 1; +} + + +/*************************************************************************** + * is called, when the df-command writes on StdOut or StdErr +**/ +void DiskList::receivedDFStdErrOut(KProcess *, char *data, int len ) +{ + kdDebug() << k_funcinfo << endl; + + + /* ATTENTION: StdERR no longer connected to this... + * Do we really need StdErr?? on HP-UX there was eg. a line + * df: /home_tu1/ijzerman/floppy: Stale NFS file handle + * but this shouldn't cause a real problem + */ + + + QString tmp = QString::fromLatin1(data, len); + dfStringErrOut.append(tmp); +} + +/*************************************************************************** + * reads the df-commands results +**/ +int DiskList::readDF() +{ + kdDebug() << k_funcinfo << endl; + + if (readingDFStdErrOut || dfProc->isRunning()) return -1; + setenv("LANG", "en_US", 1); + setenv("LC_ALL", "en_US", 1); + setenv("LC_MESSAGES", "en_US", 1); + setenv("LC_TYPE", "en_US", 1); + setenv("LANGUAGE", "en_US", 1); + dfStringErrOut=""; // yet no data received + dfProc->clearArguments(); + (*dfProc) << "env" << "LC_ALL=POSIX" << DF_COMMAND << DF_ARGS; + if (!dfProc->start( KProcess::NotifyOnExit, KProcess::AllOutput )) + qFatal(i18n("could not execute [%s]").local8Bit().data(), DF_COMMAND); + return 1; +} + + +/*************************************************************************** + * is called, when the df-command has finished +**/ +void DiskList::dfDone() +{ + kdDebug() << k_funcinfo << endl; + + if (updatesDisabled) + return; //Don't touch the data for now.. + + readingDFStdErrOut=TRUE; + for ( DiskEntry *disk=disks->first(); disk != 0; disk=disks->next() ) + disk->setMounted(FALSE); // set all devs unmounted + + QTextStream t (dfStringErrOut, IO_ReadOnly); + QString s=t.readLine(); + if ( ( s.isEmpty() ) || ( s.left(10) != "Filesystem" ) ) + qFatal("Error running df command... got [%s]",s.latin1()); + while ( !t.atEnd() ) { + QString u,v; + DiskEntry *disk; + s=t.readLine(); + s=s.simplifyWhiteSpace(); + if ( !s.isEmpty() ) { + disk = new DiskEntry(); Q_CHECK_PTR(disk); + + if (s.find(BLANK)<0) // devicename was too long, rest in next line + if ( !t.eof() ) { // just appends the next line + v=t.readLine(); + s=s.append(v.latin1() ); + s=s.simplifyWhiteSpace(); + //kdDebug() << "SPECIAL GOT: [" << s << "]" << endl; + }//if silly linefeed + + //kdDebug() << "EFFECTIVELY GOT " << s.length() << " chars: [" << s << "]" << endl; + + disk->setDeviceName(s.left(s.find(BLANK)) ); + s=s.remove(0,s.find(BLANK)+1 ); + //kdDebug() << " DeviceName: [" << disk->deviceName() << "]" << endl; + + if (NO_FS_TYPE) { + //kdDebug() << "THERE IS NO FS_TYPE_FIELD!" << endl; + disk->setFsType("?"); + } else { + disk->setFsType(s.left(s.find(BLANK)) ); + s=s.remove(0,s.find(BLANK)+1 ); + }; + //kdDebug() << " FS-Type: [" << disk->fsType() << "]" << endl; + //kdDebug() << " Icon: [" << disk->iconName() << "]" << endl; + + u=s.left(s.find(BLANK)); + disk->setKBSize(u.toInt() ); + s=s.remove(0,s.find(BLANK)+1 ); + //kdDebug() << " Size: [" << disk->kBSize() << "]" << endl; + + u=s.left(s.find(BLANK)); + disk->setKBUsed(u.toInt() ); + s=s.remove(0,s.find(BLANK)+1 ); + //kdDebug() << " Used: [" << disk->kBUsed() << "]" << endl; + + u=s.left(s.find(BLANK)); + disk->setKBAvail(u.toInt() ); + s=s.remove(0,s.find(BLANK)+1 ); + //kdDebug() << " Avail: [" << disk->kBAvail() << "]" << endl; + + + s=s.remove(0,s.find(BLANK)+1 ); // delete the capacity 94% + disk->setMountPoint(s); + //kdDebug() << " MountPoint: [" << disk->mountPoint() << "]" << endl; + + if ( (disk->kBSize() > 0) + && (disk->deviceName() != "none") + && (disk->fsType() != "swap") + && (disk->fsType() != "sysfs") + && (disk->mountPoint() != "/dev/swap") + && (disk->mountPoint() != "/dev/pts") + && (disk->mountPoint() != "/dev/shm") + && (disk->mountPoint().find("/proc") == -1 ) ) { + disk->setMounted(TRUE); // its now mounted (df lists only mounted) + replaceDeviceEntry(disk); + } else + delete disk; + + }//if not header + }//while further lines available + + readingDFStdErrOut=FALSE; + loadSettings(); //to get the mountCommands + emit readDFDone(); +} + + +void DiskList::deleteAllMountedAt(const QString &mountpoint) +{ + kdDebug() << k_funcinfo << endl; + + + for ( DiskEntry *item = disks->first(); item; ) + { + if (item->mountPoint() == mountpoint ) { + kdDebug() << "delete " << item->deviceName() << endl; + disks->remove(item); + item = disks->current(); + } else + item = disks->next(); + } +} + +/*************************************************************************** + * updates or creates a new DiskEntry in the KDFList and TabListBox +**/ +void DiskList::replaceDeviceEntry(DiskEntry *disk) +{ + //kdDebug() << k_funcinfo << disk->deviceRealName() << " " << disk->realMountPoint() << endl; + + // + // The 'disks' may already already contain the 'disk'. If it do + // we will replace some data. Otherwise 'disk' will be added to the list + // + + // + // 1999-27-11 Espen Sand: + // I can't get find() to work. The Disks::compareItems(..) is + // never called. + // + //int pos=disks->find(disk); + + QString deviceRealName = disk->deviceRealName(); + QString realMountPoint = disk->realMountPoint(); + + int pos = -1; + for( u_int i=0; i<disks->count(); i++ ) + { + DiskEntry *item = disks->at(i); + int res = deviceRealName.compare( item->deviceRealName() ); + if( res == 0 ) + { + res = realMountPoint.compare( item->realMountPoint() ); + } + if( res == 0 ) + { + pos = i; + break; + } + } + + if ((pos == -1) && (disk->mounted()) ) + // no matching entry found for mounted disk + if ((disk->fsType() == "?") || (disk->fsType() == "cachefs")) { + //search for fitting cachefs-entry in static /etc/vfstab-data + DiskEntry* olddisk = disks->first(); + while (olddisk != 0) { + int p; + // cachefs deviceNames have no / behind the host-column + // eg. /cache/cache/.cfs_mnt_points/srv:_home_jesus + // ^ ^ + QString odiskName = olddisk->deviceName(); + int ci=odiskName.find(':'); // goto host-column + while ((ci =odiskName.find('/',ci)) > 0) { + odiskName.replace(ci,1,"_"); + }//while + // check if there is something that is exactly the tail + // eg. [srv:/tmp3] is exact tail of [/cache/.cfs_mnt_points/srv:_tmp3] + if ( ( (p=disk->deviceName().findRev(odiskName + ,disk->deviceName().length()) ) + != -1) + && (p + odiskName.length() + == disk->deviceName().length()) ) + { + pos = disks->at(); //store the actual position + disk->setDeviceName(olddisk->deviceName()); + olddisk=0; + } else + olddisk=disks->next(); + }// while + }// if fsType == "?" or "cachefs" + + +#ifdef NO_FS_TYPE + if (pos != -1) { + DiskEntry * olddisk = disks->at(pos); + if (olddisk) + disk->setFsType(olddisk->fsType()); + } +#endif + + if (pos != -1) { // replace + DiskEntry * olddisk = disks->at(pos); + if ( (-1!=olddisk->mountOptions().find("user")) && + (-1==disk->mountOptions().find("user")) ) { + // add "user" option to new diskEntry + QString s=disk->mountOptions(); + if (s.length()>0) s.append(","); + s.append("user"); + disk->setMountOptions(s); + } + disk->setMountCommand(olddisk->mountCommand()); + disk->setUmountCommand(olddisk->umountCommand()); + + // Same device name, but maybe one is a symlink and the other is its target + // Keep the shorter one then, /dev/hda1 looks better than /dev/ide/host0/bus0/target0/lun0/part1 + if ( disk->deviceName().length() > olddisk->deviceName().length() ) + disk->setDeviceName(olddisk->deviceName()); + + //FStab after an older DF ... needed for critFull + //so the DF-KBUsed survive a FStab lookup... + //but also an unmounted disk may then have a kbused set... + if ( (olddisk->mounted()) && (!disk->mounted()) ) { + disk->setKBSize(olddisk->kBSize()); + disk->setKBUsed(olddisk->kBUsed()); + disk->setKBAvail(olddisk->kBAvail()); + } + if ( (olddisk->percentFull() != -1) && + (olddisk->percentFull() < FULL_PERCENT) && + (disk->percentFull() >= FULL_PERCENT) ) { + kdDebug() << "Device " << disk->deviceName() + << " is critFull! " << olddisk->percentFull() + << "--" << disk->percentFull() << endl; + emit criticallyFull(disk); + } + disks->remove(pos); // really deletes old one + disks->insert(pos,disk); + } else { + disks->append(disk); + }//if + +} + +#include "disklist.moc" + + + + + + |