diff options
Diffstat (limited to 'kicker/applets/naughty')
-rw-r--r-- | kicker/applets/naughty/Makefile.am | 30 | ||||
-rw-r--r-- | kicker/applets/naughty/NaughtyApplet.cpp | 223 | ||||
-rw-r--r-- | kicker/applets/naughty/NaughtyApplet.h | 76 | ||||
-rw-r--r-- | kicker/applets/naughty/NaughtyConfigDialog.cpp | 98 | ||||
-rw-r--r-- | kicker/applets/naughty/NaughtyConfigDialog.h | 58 | ||||
-rw-r--r-- | kicker/applets/naughty/NaughtyProcessMonitor.cpp | 475 | ||||
-rw-r--r-- | kicker/applets/naughty/NaughtyProcessMonitor.h | 76 | ||||
-rw-r--r-- | kicker/applets/naughty/configure.in.in | 5 | ||||
-rw-r--r-- | kicker/applets/naughty/naughty-happy.png | bin | 0 -> 457 bytes | |||
-rw-r--r-- | kicker/applets/naughty/naughty-sad.png | bin | 0 -> 440 bytes | |||
-rw-r--r-- | kicker/applets/naughty/naughtyapplet.desktop | 131 |
11 files changed, 1172 insertions, 0 deletions
diff --git a/kicker/applets/naughty/Makefile.am b/kicker/applets/naughty/Makefile.am new file mode 100644 index 000000000..533df19c3 --- /dev/null +++ b/kicker/applets/naughty/Makefile.am @@ -0,0 +1,30 @@ +pic_DATA = naughty-happy.png naughty-sad.png +picdir = $(kde_datadir)/naughtyapplet/pics + +INCLUDES = -I$(top_srcdir)/kicker/libkicker $(all_includes) + +kde_module_LTLIBRARIES = naughty_panelapplet.la + +naughty_panelapplet_la_SOURCES = \ + NaughtyProcessMonitor.cpp \ + NaughtyConfigDialog.cpp \ + NaughtyApplet.cpp + +METASOURCES = AUTO + +noinst_HEADERS = \ + NaughtyProcessMonitor.h \ + NaughtyConfigDialog.h \ + NaughtyApplet.h + +lnkdir = $(kde_datadir)/kicker/applets +lnk_DATA = naughtyapplet.desktop + +EXTRA_DIST = $(lnk_DATA) + +naughty_panelapplet_la_LDFLAGS = -module $(KDE_PLUGIN) $(all_libraries) +naughty_panelapplet_la_LIBADD = ../../libkicker/libkickermain.la $(LIB_KDEUI) $(LIB_KVM) + +messages: rc.cpp + $(XGETTEXT) *.cpp *.h -o $(podir)/naughtyapplet.pot + diff --git a/kicker/applets/naughty/NaughtyApplet.cpp b/kicker/applets/naughty/NaughtyApplet.cpp new file mode 100644 index 000000000..c256aa36f --- /dev/null +++ b/kicker/applets/naughty/NaughtyApplet.cpp @@ -0,0 +1,223 @@ +/* + Naughty applet - Runaway process monitor for the KDE panel + + Copyright 2000 Rik Hemsley (rikkus) <rik@kde.org> + + 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 "NaughtyApplet.h" +#include "NaughtyProcessMonitor.h" +#include "NaughtyConfigDialog.h" + +#include <qmessagebox.h> +#include <qtoolbutton.h> +#include <qlayout.h> + +#include <kiconloader.h> +#include <kglobal.h> +#include <kconfig.h> +#include <kaboutapplication.h> +#include <kaboutdata.h> +#include <klocale.h> +#include <kpopupmenu.h> +#include <kmessagebox.h> +#include <qpushbutton.h> + +extern "C" +{ + KDE_EXPORT KPanelApplet* init(QWidget * parent, const QString & configFile) + { + KGlobal::locale()->insertCatalogue("naughtyapplet"); + + return new NaughtyApplet + ( + configFile, + KPanelApplet::Normal, + KPanelApplet::About | KPanelApplet::Preferences, + parent, + "naughtyapplet" + ); + } +} + +NaughtyApplet::NaughtyApplet +( + const QString & configFile, + Type t, + int actions, + QWidget * parent, + const char * name +) + : KPanelApplet(configFile, t, actions, parent, name) +{ + KGlobal::iconLoader()->addAppDir("naughtyapplet"); + setBackgroundOrigin( AncestorOrigin ); + + button_ = new SimpleButton(this); + button_->setFixedSize(20, 20); + + QVBoxLayout * layout = new QVBoxLayout(this); + layout->addWidget(button_); + + monitor_ = new NaughtyProcessMonitor(2, 20, this); + + connect + ( + button_, SIGNAL(clicked()), + this, SLOT(slotPreferences()) + ); + + connect + ( + monitor_, SIGNAL(runawayProcess(ulong, const QString &)), + this, SLOT(slotWarn(ulong, const QString &)) + ); + + connect + ( + monitor_, SIGNAL(load(uint)), + this, SLOT(slotLoad(uint)) + ); + + loadSettings(); + + monitor_->start(); +} + +NaughtyApplet::~NaughtyApplet() +{ + KGlobal::locale()->removeCatalogue("naughtyapplet"); +} + + void +NaughtyApplet::slotWarn(ulong pid, const QString & name) +{ + if (ignoreList_.contains(name)) + return; + + QString s = i18n("A program called '%1' is slowing down the others " + "on your machine. It may have a bug that is causing " + "this, or it may just be busy.\n" + "Would you like to try to stop the program?"); + + int retval = KMessageBox::warningYesNo(this, s.arg(name), QString::null, i18n("Stop"), i18n("Keep Running")); + + if (KMessageBox::Yes == retval) + monitor_->kill(pid); + else + { + s = i18n("In future, should busy programs called '%1' be ignored?"); + + retval = KMessageBox::questionYesNo(this, s.arg(name), QString::null, i18n("Ignore"), i18n("Do Not Ignore")); + + if (KMessageBox::Yes == retval) + { + ignoreList_.append(name); + config()->writeEntry("IgnoreList", ignoreList_); + config()->sync(); + } + } +} + + int +NaughtyApplet::widthForHeight(int) const +{ + return 20; +} + + int +NaughtyApplet::heightForWidth(int) const +{ + return 20; +} + + void +NaughtyApplet::slotLoad(uint l) +{ + if (l > monitor_->triggerLevel()) + button_->setPixmap(BarIcon("naughty-sad")); + else + button_->setPixmap(BarIcon("naughty-happy")); +} + + void +NaughtyApplet::about() +{ + KAboutData about + ( + "naughtyapplet", + I18N_NOOP("Naughty applet"), + "1.0", + I18N_NOOP("Runaway process catcher"), + KAboutData::License_GPL_V2, + "(C) 2000 Rik Hemsley (rikkus) <rik@kde.org>" + ); + + KAboutApplication a(&about, this); + a.exec(); +} + + void +NaughtyApplet::slotPreferences() +{ + preferences(); +} + + void +NaughtyApplet::preferences() +{ + NaughtyConfigDialog d + ( + ignoreList_, + monitor_->interval(), + monitor_->triggerLevel(), + this + ); + + QDialog::DialogCode retval = QDialog::DialogCode(d.exec()); + + if (QDialog::Accepted == retval) + { + ignoreList_ = d.ignoreList(); + monitor_->setInterval(d.updateInterval()); + monitor_->setTriggerLevel(d.threshold()); + saveSettings(); + } +} + + void +NaughtyApplet::loadSettings() +{ + ignoreList_ = config()->readListEntry("IgnoreList"); + monitor_->setInterval(config()->readUnsignedNumEntry("UpdateInterval", 2)); + monitor_->setTriggerLevel(config()->readUnsignedNumEntry("Threshold", 20)); + + // Add 'X' as a default. + if (ignoreList_.isEmpty() && !config()->hasKey("IgnoreList")) + ignoreList_.append("X"); +} + + void +NaughtyApplet::saveSettings() +{ + config()->writeEntry("IgnoreList", ignoreList_); + config()->writeEntry("UpdateInterval", monitor_->interval()); + config()->writeEntry("Threshold", monitor_->triggerLevel()); + config()->sync(); +} + +#include "NaughtyApplet.moc" + diff --git a/kicker/applets/naughty/NaughtyApplet.h b/kicker/applets/naughty/NaughtyApplet.h new file mode 100644 index 000000000..00df51ec4 --- /dev/null +++ b/kicker/applets/naughty/NaughtyApplet.h @@ -0,0 +1,76 @@ +/* + Naughty applet - Runaway process monitor for the KDE panel + + Copyright 2000 Rik Hemsley (rikkus) <rik@kde.org> + + 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. +*/ + +#ifndef NAUGHTY_H +#define NAUGHTY_H + +#include <kpanelapplet.h> +#include <qstringlist.h> + +#include "simplebutton.h" + +class NaughtyProcessMonitor; +class QPushButton; + +class NaughtyApplet : public KPanelApplet +{ + Q_OBJECT + + public: + + NaughtyApplet + ( + const QString & configFile, + Type t = Normal, + int actions = 0, + QWidget * parent = 0, + const char * name = 0 + ); + + ~NaughtyApplet(); + + virtual int widthForHeight(int h) const; + virtual int heightForWidth(int w) const; + + signals: + + void layoutChanged(); + + protected slots: + + void slotWarn(ulong pid, const QString & name); + void slotLoad(uint); + void slotPreferences(); + + protected: + + virtual void about(); + virtual void preferences(); + virtual void loadSettings(); + virtual void saveSettings(); + + private: + + NaughtyProcessMonitor * monitor_; + SimpleButton * button_; + QStringList ignoreList_; +}; + +#endif diff --git a/kicker/applets/naughty/NaughtyConfigDialog.cpp b/kicker/applets/naughty/NaughtyConfigDialog.cpp new file mode 100644 index 000000000..e03a955cc --- /dev/null +++ b/kicker/applets/naughty/NaughtyConfigDialog.cpp @@ -0,0 +1,98 @@ +/* + Naughty applet - Runaway process monitor for the KDE panel + + Copyright 2000 Rik Hemsley (rikkus) <rik@kde.org> + + 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 <keditlistbox.h> +#include <knuminput.h> +#include <klocale.h> +#include <qvbox.h> + +#include "NaughtyConfigDialog.h" +#include "NaughtyConfigDialog.moc" + +NaughtyConfigDialog::NaughtyConfigDialog +( + const QStringList & items, + uint updateInterval, + uint threshold, + QWidget * parent, + const char * name +) + : + KDialogBase + ( + parent, + name, + true, + i18n("Configuration"), + KDialogBase::Ok | KDialogBase::Cancel, + KDialogBase::Ok, + true + ) +{ + QVBox * v = new QVBox(this); + setMainWidget(v); + + kini_updateInterval_ = new KIntNumInput(updateInterval, v); + kini_threshold_ = new KIntNumInput(kini_updateInterval_, threshold, v); + + kini_updateInterval_ ->setLabel(i18n("&Update interval:")); + kini_threshold_ ->setLabel(i18n("CPU &load threshold:")); + + kini_updateInterval_ ->setRange(1, 20); + kini_threshold_ ->setRange(10, 1000); + + listBox_ = new KEditListBox + (i18n("&Programs to Ignore"), + v, + "naughty config dialog ignore listbox", + false, + KEditListBox::Add | KEditListBox::Remove + ); + + listBox_->insertStringList(items); +} + +NaughtyConfigDialog::~NaughtyConfigDialog() +{ +} + + uint +NaughtyConfigDialog::updateInterval() const +{ + return uint(kini_updateInterval_->value()); +} + + uint +NaughtyConfigDialog::threshold() const +{ + return uint(kini_threshold_->value()); +} + + QStringList +NaughtyConfigDialog::ignoreList() const +{ + QStringList retval; + + for (int i = 0; i < listBox_->count(); i++) + retval << listBox_->text(i); + + return retval; +} + diff --git a/kicker/applets/naughty/NaughtyConfigDialog.h b/kicker/applets/naughty/NaughtyConfigDialog.h new file mode 100644 index 000000000..485cbf14f --- /dev/null +++ b/kicker/applets/naughty/NaughtyConfigDialog.h @@ -0,0 +1,58 @@ +/* + Naughty applet - Runaway process monitor for the KDE panel + + Copyright 2000 Rik Hemsley (rikkus) <rik@kde.org> + + 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. +*/ + +#ifndef NAUGHTY_CONFIG_DIALOG_H +#define NAUGHTY_CONFIG_DIALOG_H + +#include <kdialogbase.h> + +class KEditListBox; +class KIntNumInput; + +class NaughtyConfigDialog : public KDialogBase +{ + Q_OBJECT + + public: + + NaughtyConfigDialog + ( + const QStringList & items, + uint interval, + uint threshold, + QWidget * parent = 0, + const char * name = 0 + ); + + ~NaughtyConfigDialog(); + + QStringList ignoreList() const; + uint updateInterval() const; + uint threshold() const; + + private: + + KEditListBox * listBox_; + + KIntNumInput * kini_updateInterval_; + KIntNumInput * kini_threshold_; +}; + +#endif diff --git a/kicker/applets/naughty/NaughtyProcessMonitor.cpp b/kicker/applets/naughty/NaughtyProcessMonitor.cpp new file mode 100644 index 000000000..f9d352902 --- /dev/null +++ b/kicker/applets/naughty/NaughtyProcessMonitor.cpp @@ -0,0 +1,475 @@ +/* + Naughty applet - Runaway process monitor for the KDE panel + + Copyright 2000 Rik Hemsley (rikkus) <rik@kde.org> + + 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. +*/ + +/* OpenBSD support by Jean-Yves Burlett <jean-yves@burlett.org> */ + +#ifdef __OpenBSD__ +#include <sys/param.h> +#include <sys/proc.h> +#include <sys/sysctl.h> +#include <sys/ucred.h> +#include <sys/dkstat.h> +#include <stdlib.h> +#endif + +#include <sys/types.h> +#include <signal.h> +#include <unistd.h> + +#include <qfile.h> +#include <qstring.h> +#include <qstringlist.h> +#include <qtextstream.h> +#include <qdir.h> +#include <qtimer.h> +#include <qmap.h> +#include <qdatetime.h> + +#include <klocale.h> + +#include "NaughtyProcessMonitor.h" + +class NaughtyProcessMonitorPrivate +{ + public: + + NaughtyProcessMonitorPrivate() + : interval_(0), + timer_(0), + oldLoad_(0), + triggerLevel_(0) + { + } + + ~NaughtyProcessMonitorPrivate() + { + // Empty. + } + + uint interval_; + QTimer * timer_; + QMap<ulong, uint> loadMap_; + QMap<ulong, uint> scoreMap_; +#ifdef __OpenBSD__ + QMap<ulong, uint> cacheLoadMap_; + QMap<ulong, uid_t> uidMap_; +#endif + uint oldLoad_; + uint triggerLevel_; + + private: + + NaughtyProcessMonitorPrivate(const NaughtyProcessMonitorPrivate &); + + NaughtyProcessMonitorPrivate & operator = + (const NaughtyProcessMonitorPrivate &); +}; + +NaughtyProcessMonitor::NaughtyProcessMonitor + ( + uint interval, + uint triggerLevel, + QObject * parent, + const char * name + ) + : QObject(parent, name) +{ + d = new NaughtyProcessMonitorPrivate; + d->interval_ = interval * 1000; + d->triggerLevel_ = triggerLevel; + d->timer_ = new QTimer(this); + connect(d->timer_, SIGNAL(timeout()), this, SLOT(slotTimeout())); +} + +NaughtyProcessMonitor::~NaughtyProcessMonitor() +{ + delete d; +} + + void +NaughtyProcessMonitor::start() +{ + d->timer_->start(d->interval_, true); +} + + void +NaughtyProcessMonitor::stop() +{ + d->timer_->stop(); +} + + uint +NaughtyProcessMonitor::interval() const +{ + return d->interval_ / 1000; +} + + void +NaughtyProcessMonitor::setInterval(uint i) +{ + stop(); + d->interval_ = i * 1000; + start(); +} + + uint +NaughtyProcessMonitor::triggerLevel() const +{ + return d->triggerLevel_; +} + + void +NaughtyProcessMonitor::setTriggerLevel(uint i) +{ + d->triggerLevel_ = i; +} + + void +NaughtyProcessMonitor::slotTimeout() +{ + uint cpu = cpuLoad(); + + emit(load(cpu)); + + if (cpu > d->triggerLevel_ * (d->interval_ / 1000)) + { + uint load; + QValueList<ulong> l(pidList()); + + for (QValueList<ulong>::ConstIterator it(l.begin()); it != l.end(); ++it) + if (getLoad(*it, load)) + _process(*it, load); + } + + d->timer_->start(d->interval_, true); +} + + void +NaughtyProcessMonitor::_process(ulong pid, uint load) +{ + if (!d->loadMap_.contains(pid)) + { + d->loadMap_.insert(pid, load); + return; + } + + uint oldLoad = d->loadMap_[pid]; + bool misbehaving = (load - oldLoad) > 40 * (d->interval_ / 1000); + bool wasMisbehaving = d->scoreMap_.contains(pid); + + if (misbehaving) + if (wasMisbehaving) + { + d->scoreMap_.replace(pid, d->scoreMap_[pid] + 1); + if (canKill(pid)) + emit(runawayProcess(pid, processName(pid))); + } + else + d->scoreMap_.insert(pid, 1); + else + if (wasMisbehaving) + d->scoreMap_.remove(pid); + + d->loadMap_.replace(pid, load); +} + +// Here begins the set of system-specific methods. + + bool +NaughtyProcessMonitor::canKill(ulong pid) const +{ +#ifdef __linux__ + QFile f("/proc/" + QString::number(pid) + "/status"); + + if (!f.open(IO_ReadOnly)) + return false; + + QTextStream t(&f); + + QString s; + + while (!t.atEnd() && s.left(4) != "Uid:") + s = t.readLine(); + + QStringList l(QStringList::split('\t', s)); + + uint a(l[1].toUInt()); + +// What are these 3 fields for ? Would be nice if the Linux kernel docs +// were complete, eh ? +// uint b(l[2].toUInt()); +// uint c(l[3].toUInt()); +// uint d(l[4].toUInt()); + + return geteuid() == a; +#elif defined(__OpenBSD__) + // simply check if entry exists in the uid map and use it + if (!d->uidMap_.contains(pid)) + return false ; + + return geteuid () == d->uidMap_[pid] ; +#else + Q_UNUSED( pid ); + return false; +#endif +} + + QString +NaughtyProcessMonitor::processName(ulong pid) const +{ +#if defined(__linux__) || defined(__OpenBSD__) +#ifdef __linux__ + QFile f("/proc/" + QString::number(pid) + "/cmdline"); + + if (!f.open(IO_ReadOnly)) + return i18n("Unknown"); + + QCString s; + + while (true) + { + int c = f.getch(); + + // Stop at NUL + if (c == -1 || char(c) == '\0') + break; + else + s += char(c); + } + + // Now strip 'kdeinit:' prefix. + QString unicode(QString::fromLocal8Bit(s)); + +#elif defined(__OpenBSD__) + int mib[4] ; + size_t size ; + char **argv ; + + // fetch argv for the process `pid' + + mib[0] = CTL_KERN ; + mib[1] = KERN_PROC_ARGS ; + mib[2] = pid ; + mib[3] = KERN_PROC_ARGV ; + + // we assume argv[0]'s size will be less than one page + + size = getpagesize () ; + argv = (char **)calloc (size, sizeof (char)) ; + size-- ; // ensure argv is ended by 0 + if (-1 == sysctl (mib, 4, argv, &size, NULL, 0)) { + free (argv) ; + return i18n("Unknown") ; + } + + // Now strip 'kdeinit:' prefix. + QString unicode(QString::fromLocal8Bit(argv[0])); + + free (argv) ; +#endif + + QStringList parts(QStringList::split(' ', unicode)); + + QString processName = parts[0] == "kdeinit:" ? parts[1] : parts[0]; + + int lastSlash = processName.findRev('/'); + + // Get basename, if there's a path. + if (-1 != lastSlash) + processName = processName.mid(lastSlash + 1); + + return processName; + +#else + Q_UNUSED( pid ); + return QString::null; +#endif +} + + uint +NaughtyProcessMonitor::cpuLoad() const +{ +#ifdef __linux__ + QFile f("/proc/stat"); + + if (!f.open(IO_ReadOnly)) + return 0; + + bool forgetThisOne = 0 == d->oldLoad_; + + QTextStream t(&f); + + QString s = t.readLine(); + + QStringList l(QStringList::split(' ', s)); + + uint user = l[1].toUInt(); + uint sys = l[3].toUInt(); + + uint load = user + sys; + uint diff = load - d->oldLoad_; + d->oldLoad_ = load; + + return (forgetThisOne ? 0 : diff); +#elif defined(__OpenBSD__) + int mib[2] ; + long cp_time[CPUSTATES] ; + size_t size ; + uint load, diff ; + bool forgetThisOne = 0 == d->oldLoad_; + + // fetch CPU time statistics + + mib[0] = CTL_KERN ; + mib[1] = KERN_CPTIME ; + + size = CPUSTATES * sizeof(long) ; + + if (-1 == sysctl (mib, 2, cp_time, &size, NULL, 0)) + return 0 ; + + load = cp_time[CP_USER] + cp_time[CP_SYS] ; + diff = load - d->oldLoad_ ; + d->oldLoad_ = load ; + + return (forgetThisOne ? 0 : diff); +#else + return 0; +#endif +} + + QValueList<ulong> +NaughtyProcessMonitor::pidList() const +{ +#ifdef __linux__ + QStringList dl(QDir("/proc").entryList()); + + QValueList<ulong> pl; + + for (QStringList::ConstIterator it(dl.begin()); it != dl.end(); ++it) + if (((*it)[0].isDigit())) + pl << (*it).toUInt(); + + return pl; +#elif defined(__OpenBSD__) + int mib[3] ; + int nprocs = 0, nentries ; + size_t size ; + struct kinfo_proc *kp ; + int i ; + QValueList<ulong> l; + + // fetch number of processes + + mib[0] = CTL_KERN ; + mib[1] = KERN_NPROCS ; + + if (-1 == sysctl (mib, 2, &nprocs, &size, NULL, 0)) + return l ; + + // magic size evaluation ripped from ps + + size = (5 * nprocs * sizeof(struct kinfo_proc)) / 4 ; + kp = (struct kinfo_proc *)calloc (size, sizeof (char)) ; + + // fetch process info + + mib[0] = CTL_KERN ; + mib[1] = KERN_PROC ; + mib[2] = KERN_PROC_ALL ; + + if (-1 == sysctl (mib, 3, kp, &size, NULL, 0)) { + free (kp) ; + return l ; + } + + nentries = size / sizeof (struct kinfo_proc) ; + + // time statistics and euid data are fetched only for processes in + // the pidList, so, instead of doing one sysctl per process for + // getLoad and canKill calls, simply cache the data we already have. + + d->cacheLoadMap_.clear () ; + d->uidMap_.clear () ; + for (i = 0; i < nentries; i++) { + l << (unsigned long) kp[i].kp_proc.p_pid ; + d->cacheLoadMap_.insert (kp[i].kp_proc.p_pid, + (kp[i].kp_proc.p_uticks + + kp[i].kp_proc.p_sticks)) ; + d->uidMap_.insert (kp[i].kp_proc.p_pid, + kp[i].kp_eproc.e_ucred.cr_uid) ; + } + + free (kp) ; + + return l ; +#else + QValueList<ulong> l; + return l; +#endif +} + + bool +NaughtyProcessMonitor::getLoad(ulong pid, uint & load) const +{ +#ifdef __linux__ + QFile f("/proc/" + QString::number(pid) + "/stat"); + + if (!f.open(IO_ReadOnly)) + return false; + + QTextStream t(&f); + + QString line(t.readLine()); + + QStringList fields(QStringList::split(' ', line)); + + uint userTime (fields[13].toUInt()); + uint sysTime (fields[14].toUInt()); + + load = userTime + sysTime; + + return true; +#elif defined(__OpenBSD__) + // use cache + if (!d->cacheLoadMap_.contains(pid)) + return false ; + + load = d->cacheLoadMap_[pid] ; + return true ; +#else + Q_UNUSED( pid ); + Q_UNUSED( load ); + return false; +#endif +} + + bool +NaughtyProcessMonitor::kill(ulong pid) const +{ +#if defined(__linux__) || defined(__OpenBSD__) + return 0 == ::kill(pid, SIGKILL); +#else + Q_UNUSED( pid ); + return false; +#endif +} + +#include "NaughtyProcessMonitor.moc" diff --git a/kicker/applets/naughty/NaughtyProcessMonitor.h b/kicker/applets/naughty/NaughtyProcessMonitor.h new file mode 100644 index 000000000..d7023dbd7 --- /dev/null +++ b/kicker/applets/naughty/NaughtyProcessMonitor.h @@ -0,0 +1,76 @@ +/* + Naughty applet - Runaway process monitor for the KDE panel + + Copyright 2000 Rik Hemsley (rikkus) <rik@kde.org> + + 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. +*/ + +#ifndef NAUGHTY_PROCESS_MONITOR_H +#define NAUGHTY_PROCESS_MONITOR_H + +#include <qobject.h> + +class NaughtyProcessMonitorPrivate; + +class NaughtyProcessMonitor : public QObject +{ + Q_OBJECT + + public: + + NaughtyProcessMonitor + ( + uint interval, + uint triggerLevel, + QObject * parent = 0, + const char * name = 0 + ); + + virtual ~NaughtyProcessMonitor(); + + void start(); + void stop(); + + uint triggerLevel() const; + void setTriggerLevel(uint); + uint interval() const; + void setInterval(uint); + + virtual uint cpuLoad() const; + virtual QValueList<ulong> pidList() const; + virtual bool getLoad(ulong pid, uint & load) const; + virtual QString processName(ulong pid) const; + virtual bool canKill(ulong pid) const; + virtual bool kill(ulong pid) const; + + protected slots: + + void slotTimeout(); + + signals: + + void load(uint); + void runawayProcess(ulong pid, const QString & name); + + private: + + void _process(ulong pid, uint load); + + NaughtyProcessMonitorPrivate * d; +}; + +#endif + diff --git a/kicker/applets/naughty/configure.in.in b/kicker/applets/naughty/configure.in.in new file mode 100644 index 000000000..5847780f0 --- /dev/null +++ b/kicker/applets/naughty/configure.in.in @@ -0,0 +1,5 @@ +case "$host" in + *-*-freebsd*) LIB_KVM="-lkvm" ;; + *) LIB_KVM="" ;; +esac +AC_SUBST(LIB_KVM) diff --git a/kicker/applets/naughty/naughty-happy.png b/kicker/applets/naughty/naughty-happy.png Binary files differnew file mode 100644 index 000000000..3200b5270 --- /dev/null +++ b/kicker/applets/naughty/naughty-happy.png diff --git a/kicker/applets/naughty/naughty-sad.png b/kicker/applets/naughty/naughty-sad.png Binary files differnew file mode 100644 index 000000000..9b6541907 --- /dev/null +++ b/kicker/applets/naughty/naughty-sad.png diff --git a/kicker/applets/naughty/naughtyapplet.desktop b/kicker/applets/naughty/naughtyapplet.desktop new file mode 100644 index 000000000..f7cb6a35f --- /dev/null +++ b/kicker/applets/naughty/naughtyapplet.desktop @@ -0,0 +1,131 @@ +[Desktop Entry] +Type=Plugin +Name=Runaway Process Catcher +Name[af]=Weghardloop Proses Vanger +Name[ar]=لاقط الإجرائات الهاربة +Name[az]=İşıək Gedişat Yaxalayıcı +Name[be]=Захоп завіснуўшых працэсаў +Name[bg]=Неуправляеми процеси +Name[bn]=অনিয়ন্ত্রিত প্রসেস প্রহরী +Name[bs]=Hvatač odbjeglih procesa +Name[ca]=Capturador de processos descontrolats +Name[cs]=Odchytávač chybných procesů +Name[csb]=Jachtôrz zagùbionëch procesów +Name[cy]=Arhosydd Prosesau Di-derfyn +Name[da]=Indfanger af løbsk-kørte processer +Name[de]=Beenden unkontrollierter Prozesse +Name[el]=Runaway Έλεγχος Διεργασιών +Name[eo]=Kaptilo por eskapitaj procezoj +Name[es]=Capturador de procesos desbocados +Name[et]=Hanguvate protsesside püüdja +Name[eu]=Ataza eroen harrapatzailea +Name[fa]=گیرندۀ فرآیند فراری +Name[fi]=Karanneiden prosessien kiinniottaja +Name[fr]=Détecteur de processus fous +Name[fy]=Processenmonitor +Name[ga]=Sriantóir na bPróiseas Éalaitheach +Name[gl]=Detector de Procesos Estragados +Name[he]=תופס תהליכים נמלטים +Name[hi]=रनअवे प्रॉसेस कैचर +Name[hr]=Hvatač odbjeglih procesa +Name[hu]=Folyamatszabályozó +Name[is]=Ferlafangari +Name[it]=Rilevatore di processi impazziti +Name[ja]=手に負えないプロセスのキャッチャー +Name[kk]=Жаңылыс процесстерді байқаушы +Name[km]=ឧបករណ៍ចាប់យកដំណើរការដែលមិនអាចបញ្ជាបាន +Name[lo]=ດັກຈັບໂປຣເສດ +Name[lt]=Pabėgusių procesų gaudyklė +Name[lv]=Nevadāmu Procesu Savācējs +Name[mk]=Фаќач на процеси бегалци +Name[mn]=Удирдлагагүй процессуудыг төгсгөх +Name[ms]=Penangkap Proses Luar Kawalan +Name[mt]=Programm biex Jaqbad Proċessi Maħruba +Name[nb]=Fanger løpske prosesser +Name[nds]=Dörgahn Perzessen infangen +Name[ne]=रन वे प्रोसेस क्याचर +Name[nl]=Processenmonitor +Name[nn]=Løpsk prosess-fangar +Name[nso]=Moswari wa Tiragalo yeo e Tshabago +Name[pa]=ਬੇਕਾਬੂ ਕਾਰਜ ਸ਼ਿਕਾਰੀ +Name[pl]=Łowca zagubionych procesów +Name[pt]=Colector de Processos em Fuga +Name[pt_BR]=Captura de processos +Name[ro]=Monitor de procese +Name[ru]=Сторож сбойных процессов +Name[rw]=Mufata Igikorwa Ntagenzura +Name[se]=Báhtaran proseassaid dustejeaddji +Name[sk]=Zachytenie chybných procesov +Name[sl]=Prestrezovalnik pobeglih procesov +Name[sr]=Хватач одбеглих процеса +Name[sr@Latn]=Hvatač odbeglih procesa +Name[sv]=Fånga bortsprungna processer +Name[ta]=ஓடுபாதை செயல் பிடிப்பான் +Name[tg]=Дастгиркунандаи протсессҳои қарорӣ +Name[th]=ดักการจบโปรเซส +Name[tr]=Sorunlu Süreç Yakalayıcı +Name[tt]=Içqınğan Eşlänü Totqıç +Name[uk]=Захоплювач процесів-дезертирів +Name[ven]=TShitenwa tsha Catcher +Name[vi]=Bắt Tiến trình Chạy trốn +Name[wa]=Troûleu d' sot processus +Name[zh_CN]=落跑进程捕捉器 +Name[zh_TW]=失控程式捕捉器 +Name[zu]=Umbambi wenqubo ebalekayo +Comment=Detect and end broken processes which consume too much CPU time +Comment[af]=Spoor stukkende prosesse op wat te veel CPU tyd opneem en stop hulle +Comment[ar]=إكتشف و أنهي الإجرائات المقطوعة اللتي تستهلك الكثير من وقت تشغيل وحدة المعالجة المركزية +Comment[be]=Вызначае і забівае зламаныя працэсы, якія выкарыстоўваюць працэсар надта моцна +Comment[bg]=Намиране и прекратяване на процеси, които консумират твърде много ресурси +Comment[bs]=Otkrij i završi neispravne procese koji zauzimaju previše CPU vremena +Comment[ca]=Detecta i finalitza processos espatllats que consumeixen massa temps de CPU +Comment[cs]=Zjištění a ukončení poškozených procesů ubírajících výkon +Comment[csb]=Òdnajdiwô ë kùńczi niesprôwné procesë, jaczé brëkùją za wiele procesora +Comment[da]=Detekterer og afslutter fejlagtige processer som bruger for meget processortid +Comment[de]=Erkennen und Beenden fehlerhafter Prozesse, die zu viel Rechenzeit verbrauchen +Comment[el]=Ανίχνευση και τερματισμός διεργασιών που καταναλώνουν μεγάλο χρόνο του επεξεργαστή +Comment[eo]=Detekti kaj mortigi difektitajn procezojn konsumante tro da procezilo-tempon +Comment[es]=Detectar procesos rotos que consumen demasiado tiempo del procesador +Comment[et]=Liialt protsessoriaega kulutavate katkiste rakenduste avastamine ja nende töö lõpetamine +Comment[eu]=Detektatu eta amaitu CPU gehiegi erabiltzen ari diren prozesuak +Comment[fa]=آشکارسازی و پایان فرآیندهای قطعشده، که زمان خیلی زیاد واحد پردازش مرکزی را مصرف میکند. +Comment[fi]=Tunnista ja lopeta rikkinäiset prosessit, jotka kuluttavat liikaa laskentatehoa. +Comment[fr]=Détection et arrêt des programmes consommant trop de ressources du processeur +Comment[fy]=Untdekke en stopje alle brutsen prosessen dy tefolle prosessortiid konsumearje +Comment[gl]=Detecta e mata procesos estragados que consumen tempo de CPU +Comment[he]=זהה וסגור תהליכים שצורכים יותר מדי זמן מעבד +Comment[hr]=Otkrivanje i završavanje nedovršenih procesa koji troše previše procesorskog vremena +Comment[hu]=A túl sok processzoridőt lefoglaló folyamatok meghatározása és bezárása +Comment[is]=Uppgötvaðu og slökktu á rofnum ferlum sem taka of mikinn örgjörvatíma +Comment[it]=Trova e termina i processi impazziti che consuma troppo processore +Comment[ja]=CPU 時間を無駄に消費する壊れたプロセスを見つけて終了させる +Comment[kk]=Проңессорды көп жұмсайтын процессарды табу және жою +Comment[km]=រក និងបញ្ចប់ដំណើរការខូចដែលប្រើពេលវេលា CPU ច្រើនពេក +Comment[lt]=Aptikti ir užbaigti sugadintus procesus, kurie suryja per daug CPU laiko +Comment[mk]=Откривање и прекинување на нефункционални процеси што го трошат времето на процесорот +Comment[nb]=Finn og avslutt løpske prosesser som tar for mye prosessorkraft +Comment[nds]=Schaadhaftig Perzessen, de to veel Rekentiet bruukt, opdecken un beennen +Comment[ne]=प्रसस्त CPU समय खपत गर्ने कमजोर प्रक्रिया पत्ता लगाउनुहोस् र अन्त्य गर्नुहोस् +Comment[nl]=Detecteer en stop gebroken processen die teveel processortijd consumeren +Comment[nn]=Finn og avslutt løpske prosessar som tek for myjke prosessorkraft. +Comment[pl]=Wykrywa i kończy niesprawne procesy, które zużywają za dużo procesora +Comment[pt]=Detectar e terminar os processos com problemas que estejam a consumir demasiado CPU +Comment[pt_BR]=Detecta e finaliza processos quebrados que consomem muito tempo de CPU +Comment[ro]=Detectează și termină procese defecte care consumă prea mult CPU +Comment[ru]=Обнаружение и завершение процессов, требующим слишком много времени процессора +Comment[se]=Gávnna jea heaittit reakčanan proseassaid mat geavahit menddo olu CPU-áiggi +Comment[sk]=Zistenie a ukončenie procesov, ktoré spotrebúvajú priveľa času CPU +Comment[sl]=Zaznavanje in pobijanje procesov, ki porabljajo preveč procesorskega časa +Comment[sr]=Детектује и окончава покварене процесе који одузимају превише процесорског времена +Comment[sr@Latn]=Detektuje i okončava pokvarene procese koji oduzimaju previše procesorskog vremena +Comment[sv]=Detekterar och avslutar felaktiga processer som använder för mycket processortid +Comment[th]=ตรวจจับและจบโปรเซสที่เสียหาย ซึ่งใช้เวลาของหน่วยประมวลผลมากเกินไป +Comment[tr]=Sorunlu ve fazla işlemci gücü harcayan programları bulup yokeder +Comment[uk]=Виявлення і припинення процесів, які споживають забагато часу процесора +Comment[vi]=Phát hiện và ngừng các tiến trình gây lãng phí bộ vi xử lý +Comment[wa]=Trove et arestêye les schetés processus k' eployèt trop di tins CPU +Comment[zh_CN]=检测并结束占用太多 CPU 时间的进程 +Comment[zh_TW]=偵測並終結浪費多數 CPU 時間的破損程序 +Icon=runprocesscatcher +X-KDE-Library=naughty_panelapplet +X-KDE-UniqueApplet=true |