Changeset View
Changeset View
Standalone View
Standalone View
runners/kill/killrunner.cpp
1 | /* Copyright 2009 Jan Gerrit Marker <jangerrit@weiler-marker.com> | 1 | /* Copyright 2009 Jan Gerrit Marker <jangerrit@weiler-marker.com> | ||
---|---|---|---|---|---|
2 | * Copyright 2020 Alexander Lohnau <alexander.lohnau@gmx.de> | ||||
2 | * | 3 | * | ||
3 | * This library is free software; you can redistribute it and/or | 4 | * This library is free software; you can redistribute it and/or | ||
4 | * modify it under the terms of the GNU Lesser General Public | 5 | * modify it under the terms of the GNU Lesser General Public | ||
5 | * License as published by the Free Software Foundation; either | 6 | * License as published by the Free Software Foundation; either | ||
6 | * version 2.1 of the License, or (at your option) version 3, or any | 7 | * version 2.1 of the License, or (at your option) version 3, or any | ||
7 | * later version accepted by the membership of KDE e.V. (or its | 8 | * later version accepted by the membership of KDE e.V. (or its | ||
8 | * successor approved by the membership of KDE e.V.), which shall | 9 | * successor approved by the membership of KDE e.V.), which shall | ||
9 | * act as a proxy defined in Section 6 of version 3 of the license. | 10 | * act as a proxy defined in Section 6 of version 3 of the license. | ||
Show All 9 Lines | |||||
19 | 20 | | |||
20 | #include "killrunner.h" | 21 | #include "killrunner.h" | ||
21 | 22 | | |||
22 | #include <QAction> | 23 | #include <QAction> | ||
23 | #include <QDebug> | 24 | #include <QDebug> | ||
24 | #include <QIcon> | 25 | #include <QIcon> | ||
25 | 26 | | |||
26 | #include <KProcess> | 27 | #include <KProcess> | ||
27 | #include <KUser> | 28 | #include <KAuth> | ||
28 | #include <kauth.h> | | |||
29 | #include <KLocalizedString> | 29 | #include <KLocalizedString> | ||
30 | 30 | | |||
31 | #include "processcore/processes.h" | 31 | #include <processcore/processes.h> | ||
32 | #include "processcore/process.h" | 32 | #include <processcore/process.h> | ||
33 | 33 | | |||
34 | K_EXPORT_PLASMA_RUNNER(kill, KillRunner) | 34 | K_EXPORT_PLASMA_RUNNER(kill, KillRunner) | ||
35 | 35 | | |||
36 | KillRunner::KillRunner(QObject *parent, const QVariantList& args) | 36 | KillRunner::KillRunner(QObject *parent, const QVariantList &args) | ||
37 | : Plasma::AbstractRunner(parent, args), | 37 | : Plasma::AbstractRunner(parent, args), m_processes(nullptr) | ||
38 | m_processes(nullptr) | | |||
39 | { | 38 | { | ||
40 | Q_UNUSED(args); | 39 | setObjectName(QStringLiteral("Kill Runner")); | ||
41 | setObjectName( QLatin1String("Kill Runner") ); | 40 | | ||
42 | reloadConfiguration(); | 41 | addAction(QStringLiteral("SIGTERM"), QIcon::fromTheme(QStringLiteral("application-exit")), i18n("Send SIGTERM"))->setData(15); | ||
42 | addAction(QStringLiteral("SIGKILL"), QIcon::fromTheme(QStringLiteral("process-stop")), i18n("Send SIGKILL"))->setData(9); | ||||
43 | m_actionList = {action(QStringLiteral("SIGTERM")), action(QStringLiteral("SIGKILL"))}; | ||||
43 | 44 | | |||
44 | connect(this, &Plasma::AbstractRunner::prepare, this, &KillRunner::prep); | 45 | connect(this, &Plasma::AbstractRunner::prepare, this, &KillRunner::prep); | ||
45 | connect(this, &Plasma::AbstractRunner::teardown, this, &KillRunner::cleanup); | 46 | connect(this, &Plasma::AbstractRunner::teardown, this, &KillRunner::cleanup); | ||
46 | 47 | | |||
47 | m_delayedCleanupTimer.setInterval(50); | 48 | m_delayedCleanupTimer.setInterval(50); | ||
48 | m_delayedCleanupTimer.setSingleShot(true); | 49 | m_delayedCleanupTimer.setSingleShot(true); | ||
49 | connect(&m_delayedCleanupTimer, &QTimer::timeout, this, &KillRunner::cleanup); | 50 | connect(&m_delayedCleanupTimer, &QTimer::timeout, this, &KillRunner::cleanup); | ||
50 | } | 51 | } | ||
51 | 52 | | |||
52 | KillRunner::~KillRunner() | 53 | KillRunner::~KillRunner() = default; | ||
53 | { | | |||
54 | } | | |||
55 | 54 | | |||
56 | 55 | | |||
57 | void KillRunner::reloadConfiguration() | 56 | void KillRunner::reloadConfiguration() | ||
58 | { | 57 | { | ||
59 | KConfigGroup grp = config(); | 58 | KConfigGroup grp = config(); | ||
60 | m_triggerWord.clear(); | 59 | m_triggerWord.clear(); | ||
61 | if (grp.readEntry(CONFIG_USE_TRIGGERWORD, true)) { | 60 | if (grp.readEntry(CONFIG_USE_TRIGGERWORD, true)) { | ||
62 | m_triggerWord = grp.readEntry(CONFIG_TRIGGERWORD, i18n("kill")) + QLatin1Char(' '); | 61 | m_triggerWord = grp.readEntry(CONFIG_TRIGGERWORD, i18n("kill")) + QLatin1Char(' '); | ||
63 | } | 62 | } | ||
63 | m_hasTrigger = !m_triggerWord.isEmpty(); | ||||
64 | 64 | | |||
65 | m_sorting = (Sort) grp.readEntry(CONFIG_SORTING, static_cast<int>(Sort::NONE)); | 65 | m_sorting = (Sort) grp.readEntry(CONFIG_SORTING, static_cast<int>(Sort::NONE)); | ||
66 | QList<Plasma::RunnerSyntax> syntaxes; | 66 | QList<Plasma::RunnerSyntax> syntaxes; | ||
67 | syntaxes << Plasma::RunnerSyntax(m_triggerWord + QStringLiteral(":q:"), | 67 | syntaxes << Plasma::RunnerSyntax(m_triggerWord + QStringLiteral(":q:"), | ||
68 | i18n("Terminate running applications whose names match the query.")); | 68 | i18n("Terminate running applications whose names match the query.")); | ||
69 | setSyntaxes(syntaxes); | 69 | setSyntaxes(syntaxes); | ||
70 | } | 70 | } | ||
71 | 71 | | |||
Show All 16 Lines | 78 | { | |||
88 | } else { | 88 | } else { | ||
89 | m_delayedCleanupTimer.stop(); | 89 | m_delayedCleanupTimer.stop(); | ||
90 | } | 90 | } | ||
91 | } | 91 | } | ||
92 | 92 | | |||
93 | void KillRunner::match(Plasma::RunnerContext &context) | 93 | void KillRunner::match(Plasma::RunnerContext &context) | ||
94 | { | 94 | { | ||
95 | QString term = context.query(); | 95 | QString term = context.query(); | ||
96 | const bool hasTrigger = !m_triggerWord.isEmpty(); | 96 | if (m_hasTrigger && !term.startsWith(m_triggerWord, Qt::CaseInsensitive)) { | ||
97 | if (hasTrigger && !term.startsWith(m_triggerWord, Qt::CaseInsensitive)) { | | |||
98 | return; | 97 | return; | ||
99 | } | 98 | } | ||
100 | 99 | | |||
101 | m_prepLock.lockForRead(); | 100 | m_prepLock.lockForRead(); | ||
102 | if (!m_processes) { | 101 | if (!m_processes) { | ||
103 | m_prepLock.unlock(); | 102 | m_prepLock.unlock(); | ||
104 | m_prepLock.lockForWrite(); | 103 | m_prepLock.lockForWrite(); | ||
105 | if (!m_processes) { | 104 | if (!m_processes) { | ||
Show All 12 Lines | |||||
118 | } | 117 | } | ||
119 | 118 | | |||
120 | QList<Plasma::QueryMatch> matches; | 119 | QList<Plasma::QueryMatch> matches; | ||
121 | const QList<KSysGuard::Process *> processlist = m_processes->getAllProcesses(); | 120 | const QList<KSysGuard::Process *> processlist = m_processes->getAllProcesses(); | ||
122 | for (const KSysGuard::Process *process : processlist) { | 121 | for (const KSysGuard::Process *process : processlist) { | ||
123 | if (!context.isValid()) { | 122 | if (!context.isValid()) { | ||
124 | return; | 123 | return; | ||
125 | } | 124 | } | ||
126 | | ||||
127 | const QString name = process->name(); | 125 | const QString name = process->name(); | ||
128 | if (!name.contains(term, Qt::CaseInsensitive)) { | 126 | if (!name.contains(term, Qt::CaseInsensitive)) { | ||
129 | //Process doesn't match the search term | | |||
130 | continue; | 127 | continue; | ||
131 | } | 128 | } | ||
132 | 129 | | |||
133 | const quint64 pid = process->pid(); | 130 | const quint64 pid = process->pid(); | ||
134 | const qlonglong uid = process->uid(); | | |||
135 | const QString user = getUserName(uid); | | |||
136 | | ||||
137 | QVariantList data; | | |||
138 | data << pid << user; | | |||
139 | | ||||
140 | Plasma::QueryMatch match(this); | 131 | Plasma::QueryMatch match(this); | ||
141 | match.setText(i18n("Terminate %1", name)); | 132 | match.setText(i18n("Terminate %1", name)); | ||
142 | match.setSubtext(i18n("Process ID: %1\nRunning as user: %2", QString::number(pid), user)); | 133 | match.setSubtext(i18n("Process ID: %1", QString::number(pid))); | ||
143 | match.setIconName(QStringLiteral("application-exit")); | 134 | match.setIconName(QStringLiteral("application-exit")); | ||
144 | match.setData(data); | 135 | match.setData(pid); | ||
145 | match.setId(name); | 136 | match.setId(name); | ||
146 | 137 | | |||
147 | // Set the relevance | 138 | // Set the relevance | ||
148 | switch (m_sorting) { | 139 | switch (m_sorting) { | ||
149 | case Sort::CPU: | 140 | case Sort::CPU: | ||
150 | match.setRelevance((process->userUsage() + process->sysUsage()) / 100); | 141 | match.setRelevance((process->userUsage() + process->sysUsage()) / 100); | ||
151 | break; | 142 | break; | ||
152 | case Sort::CPUI: | 143 | case Sort::CPUI: | ||
153 | match.setRelevance(1 - (process->userUsage() + process->sysUsage()) / 100); | 144 | match.setRelevance(1 - (process->userUsage() + process->sysUsage()) / 100); | ||
154 | break; | 145 | break; | ||
155 | case Sort::NONE: | 146 | case Sort::NONE: | ||
156 | match.setRelevance(name.compare(term, Qt::CaseInsensitive) == 0 ? 1 : 9); | 147 | match.setRelevance(name.compare(term, Qt::CaseInsensitive) == 0 ? 1 : 9); | ||
157 | break; | 148 | break; | ||
158 | } | 149 | } | ||
159 | 150 | | |||
160 | matches << match; | 151 | matches << match; | ||
161 | } | 152 | } | ||
162 | 153 | | |||
163 | qDebug() << "match count is" << matches.count(); | | |||
164 | context.addMatches(matches); | 154 | context.addMatches(matches); | ||
165 | } | 155 | } | ||
166 | 156 | | |||
167 | void KillRunner::run(const Plasma::RunnerContext &context, const Plasma::QueryMatch &match) | 157 | void KillRunner::run(const Plasma::RunnerContext &context, const Plasma::QueryMatch &match) | ||
168 | { | 158 | { | ||
169 | Q_UNUSED(context) | 159 | Q_UNUSED(context) | ||
170 | 160 | | |||
171 | QVariantList data = match.data().value<QVariantList>(); | 161 | const quint64 pid = match.data().toUInt(); | ||
172 | quint64 pid = data[0].toUInt(); | | |||
173 | // QString user = data[1].toString(); | | |||
174 | 162 | | |||
175 | int signal; | 163 | int signal; | ||
176 | if (match.selectedAction() != nullptr) { | 164 | if (match.selectedAction()) { | ||
177 | signal = match.selectedAction()->data().toInt(); | 165 | signal = match.selectedAction()->data().toInt(); | ||
178 | } else { | 166 | } else { | ||
179 | signal = 9; //default: SIGKILL | 167 | signal = 9; //default: SIGKILL | ||
180 | } | 168 | } | ||
181 | 169 | | |||
182 | QStringList args; | 170 | const QStringList args = {QStringLiteral("-%1").arg(signal), QString::number(pid)}; | ||
183 | args << QStringLiteral("-%1").arg(signal) << QStringLiteral("%1").arg(pid); | 171 | int returnCode = KProcess::execute(QStringLiteral("kill"), args); | ||
184 | KProcess process; | 172 | if (returnCode == 0) { | ||
185 | int returnCode = process.execute(QStringLiteral("kill"), args); | | |||
186 | | ||||
187 | if (returnCode == 0) | | |||
188 | { | | |||
189 | return; | 173 | return; | ||
190 | } | 174 | } | ||
191 | 175 | | |||
192 | KAuth::Action killAction = QStringLiteral("org.kde.ksysguard.processlisthelper.sendsignal"); | 176 | KAuth::Action killAction = QStringLiteral("org.kde.ksysguard.processlisthelper.sendsignal"); | ||
193 | killAction.setHelperId(QStringLiteral("org.kde.ksysguard.processlisthelper")); | 177 | killAction.setHelperId(QStringLiteral("org.kde.ksysguard.processlisthelper")); | ||
194 | killAction.addArgument(QStringLiteral("pid0"), pid); | 178 | killAction.addArgument(QStringLiteral("pid0"), pid); | ||
195 | killAction.addArgument(QStringLiteral("pidcount"), 1); | 179 | killAction.addArgument(QStringLiteral("pidcount"), 1); | ||
196 | killAction.addArgument(QStringLiteral("signal"), signal); | 180 | killAction.addArgument(QStringLiteral("signal"), signal); | ||
197 | killAction.execute(); | 181 | killAction.execute(); | ||
198 | } | 182 | } | ||
199 | 183 | | |||
200 | QList<QAction*> KillRunner::actionsForMatch(const Plasma::QueryMatch &match) | 184 | QList<QAction*> KillRunner::actionsForMatch(const Plasma::QueryMatch &match) | ||
201 | { | 185 | { | ||
202 | Q_UNUSED(match) | 186 | Q_UNUSED(match) | ||
203 | 187 | | |||
204 | QList<QAction*> ret; | 188 | return m_actionList; | ||
205 | | ||||
206 | if (!action(QStringLiteral("SIGTERM"))) { | | |||
207 | (addAction(QStringLiteral("SIGTERM"), QIcon::fromTheme(QStringLiteral("application-exit")), i18n("Send SIGTERM")))->setData(15); | | |||
208 | (addAction(QStringLiteral("SIGKILL"), QIcon::fromTheme(QStringLiteral("process-stop")), i18n("Send SIGKILL")))->setData(9); | | |||
209 | } | | |||
210 | ret << action(QStringLiteral("SIGTERM")) << action(QStringLiteral("SIGKILL")); | | |||
211 | return ret; | | |||
212 | } | | |||
213 | | ||||
214 | QString KillRunner::getUserName(qlonglong uid) | | |||
215 | { | | |||
216 | KUser user(uid); | | |||
217 | if (user.isValid()) { | | |||
218 | return user.loginName(); | | |||
219 | } | | |||
220 | qDebug() << QStringLiteral("No user with UID %1 was found").arg(uid); | | |||
221 | return QStringLiteral("root");//No user with UID uid was found, so root is used | | |||
222 | } | 189 | } | ||
223 | 190 | | |||
224 | #include "killrunner.moc" | 191 | #include "killrunner.moc" |