8
8
9
9
#include " perfrecord.h"
10
10
11
+ #include " recordhost.h"
12
+
11
13
#include < QDebug>
12
14
#include < QDir>
13
15
#include < QFileInfo>
19
21
#include < csignal>
20
22
#include < unistd.h>
21
23
22
- #include < KUser>
23
-
24
24
#include < kwindowsystem_version.h>
25
25
#if KWINDOWSYSTEM_VERSION >= QT_VERSION_CHECK(5, 101, 0)
26
26
#include < KX11Extras>
27
27
#else
28
28
#include < KWindowSystem>
29
29
#endif
30
30
31
- #include < hotspot-config.h>
32
-
33
- #include < fstream>
34
- #include < sys/stat.h>
35
-
36
31
namespace {
37
32
void createOutputFile (const QString& outputPath)
38
33
{
@@ -44,17 +39,11 @@ void createOutputFile(const QString& outputPath)
44
39
QFile::rename (outputPath, bakPath);
45
40
QFile (outputPath).open (QIODevice::WriteOnly);
46
41
}
47
-
48
- QString findPkexec ()
49
- {
50
- return QStandardPaths::findExecutable (QStringLiteral (" pkexec" ));
51
- }
52
42
}
53
43
54
- PerfRecord::PerfRecord (QObject* parent)
44
+ PerfRecord::PerfRecord (const RecordHost* host, QObject* parent)
55
45
: QObject(parent)
56
- , m_perfRecordProcess(nullptr )
57
- , m_userTerminated(false )
46
+ , m_host(host)
58
47
{
59
48
connect (&m_perfControlFifo, &PerfControlFifoWrapper::started, this ,
60
49
[this ]() { m_targetProcessForPrivilegedPerf.continueStoppedProcess (); });
@@ -72,38 +61,6 @@ PerfRecord::~PerfRecord()
72
61
}
73
62
}
74
63
75
- static bool privsAlreadyElevated ()
76
- {
77
- auto readSysctl = [](const char * path) {
78
- std::ifstream ifs {path};
79
- int i = std::numeric_limits<int >::min ();
80
- if (ifs) {
81
- ifs >> i;
82
- }
83
- return i;
84
- };
85
-
86
- bool isElevated = readSysctl (" /proc/sys/kernel/kptr_restrict" ) == 0 ;
87
- if (!isElevated) {
88
- return false ;
89
- }
90
-
91
- isElevated = readSysctl (" /proc/sys/kernel/perf_event_paranoid" ) == -1 ;
92
- if (!isElevated) {
93
- return false ;
94
- }
95
-
96
- auto checkPerms = [](const char * path) {
97
- const mode_t required = S_IRWXU | S_IRGRP | S_IXGRP | S_IROTH | S_IXOTH; // 755
98
- struct stat buf;
99
- return stat (path, &buf) == 0 && ((buf.st_mode & 07777 ) & required) == required;
100
- };
101
- static const auto paths = {" /sys/kernel/debug" , " /sys/kernel/debug/tracing" };
102
- isElevated = std::all_of (paths.begin (), paths.end (), checkPerms);
103
-
104
- return isElevated;
105
- }
106
-
107
64
bool PerfRecord::runPerf (bool elevatePrivileges, const QStringList& perfOptions, const QString& outputPath,
108
65
const QString& workingDirectory)
109
66
{
@@ -176,14 +133,14 @@ bool PerfRecord::runPerf(bool elevatePrivileges, const QStringList& perfOptions,
176
133
perfCommand += perfOptions;
177
134
178
135
if (elevatePrivileges) {
179
- const auto pkexec = findPkexec ();
136
+ const auto pkexec = m_host-> pkexecBinaryPath ();
180
137
if (pkexec.isEmpty ()) {
181
138
emit recordingFailed (tr (" The pkexec utility was not found, cannot elevate privileges." ));
182
139
return false ;
183
140
}
184
141
185
142
auto options = QStringList ();
186
- options.append (perfBinaryPath ());
143
+ options.append (m_host-> perfBinaryPath ());
187
144
options += perfCommand;
188
145
189
146
if (!m_perfControlFifo.open ()) {
@@ -198,7 +155,7 @@ bool PerfRecord::runPerf(bool elevatePrivileges, const QStringList& perfOptions,
198
155
199
156
m_perfRecordProcess->start (pkexec, options);
200
157
} else {
201
- m_perfRecordProcess->start (perfBinaryPath (), perfCommand);
158
+ m_perfRecordProcess->start (m_host-> perfBinaryPath (), perfCommand);
202
159
}
203
160
204
161
return true ;
@@ -295,106 +252,13 @@ void PerfRecord::sendInput(const QByteArray& input)
295
252
m_perfRecordProcess->write (input);
296
253
}
297
254
298
- QString PerfRecord::currentUsername ()
299
- {
300
- return KUser ().loginName ();
301
- }
302
-
303
- bool PerfRecord::canTrace (const QString& path)
304
- {
305
- const auto info = QFileInfo (QLatin1String (" /sys/kernel/debug/tracing/" ) + path);
306
- if (!info.isDir () || !info.isReadable ()) {
307
- return false ;
308
- }
309
- QFile paranoid (QStringLiteral (" /proc/sys/kernel/perf_event_paranoid" ));
310
- return paranoid.open (QIODevice::ReadOnly) && paranoid.readAll ().trimmed () == " -1" ;
311
- }
312
-
313
- static QByteArray perfOutput (const QStringList& arguments)
314
- {
315
- QProcess process;
316
-
317
- auto reportError = [&]() {
318
- qWarning () << " Failed to run perf" << process.arguments () << process.error () << process.errorString ()
319
- << process.readAllStandardError ();
320
- };
321
-
322
- QProcessEnvironment env = QProcessEnvironment::systemEnvironment ();
323
- env.insert (QStringLiteral (" LANG" ), QStringLiteral (" C" ));
324
- process.setProcessEnvironment (env);
325
-
326
- QObject::connect (&process, &QProcess::errorOccurred, &process, reportError);
327
- process.start (PerfRecord::perfBinaryPath (), arguments);
328
- if (!process.waitForFinished (1000 ) || process.exitCode () != 0 )
329
- reportError ();
330
- return process.readAllStandardOutput ();
331
- }
332
-
333
- static QByteArray perfRecordHelp ()
334
- {
335
- static const QByteArray recordHelp = []() {
336
- static QByteArray help = perfOutput ({QStringLiteral (" record" ), QStringLiteral (" --help" )});
337
- if (help.isEmpty ()) {
338
- // no man page installed, assume the best
339
- help = " --sample-cpu --switch-events" ;
340
- }
341
- return help;
342
- }();
343
- return recordHelp;
344
- }
345
-
346
- static QByteArray perfBuildOptions ()
347
- {
348
- static const QByteArray buildOptions = perfOutput ({QStringLiteral (" version" ), QStringLiteral (" --build-options" )});
349
- return buildOptions;
350
- }
351
-
352
- bool PerfRecord::canProfileOffCpu ()
353
- {
354
- return canTrace (QStringLiteral (" events/sched/sched_switch" ));
355
- }
356
-
357
255
QStringList PerfRecord::offCpuProfilingOptions ()
358
256
{
359
257
return {QStringLiteral (" --switch-events" ), QStringLiteral (" --event" ), QStringLiteral (" sched:sched_switch" )};
360
258
}
361
259
362
- bool PerfRecord::canSampleCpu ()
363
- {
364
- return perfRecordHelp ().contains (" --sample-cpu" );
365
- }
366
-
367
- bool PerfRecord::canSwitchEvents ()
368
- {
369
- return perfRecordHelp ().contains (" --switch-events" );
370
- }
371
-
372
- bool PerfRecord::canUseAio ()
373
- {
374
- return perfBuildOptions ().contains (" aio: [ on ]" );
375
- }
376
-
377
- bool PerfRecord::canCompress ()
378
- {
379
- return Zstd_FOUND && perfBuildOptions ().contains (" zstd: [ on ]" );
380
- }
381
-
382
- bool PerfRecord::canElevatePrivileges ()
383
- {
384
- return !findPkexec ().isEmpty ();
385
- }
386
-
387
- QString PerfRecord::perfBinaryPath ()
388
- {
389
- return QStandardPaths::findExecutable (QStringLiteral (" perf" ));
390
- }
391
-
392
- bool PerfRecord::isPerfInstalled ()
393
- {
394
- return !perfBinaryPath ().isEmpty ();
395
- }
396
-
397
- bool PerfRecord::actuallyElevatePrivileges (bool elevatePrivileges)
260
+ bool PerfRecord::actuallyElevatePrivileges (bool elevatePrivileges) const
398
261
{
399
- return elevatePrivileges && canElevatePrivileges () && geteuid () != 0 && !privsAlreadyElevated ();
262
+ const auto capabilities = m_host->perfCapabilities ();
263
+ return elevatePrivileges && capabilities.canElevatePrivileges && !capabilities.privilegesAlreadyElevated ;
400
264
}
0 commit comments