summaryrefslogtreecommitdiffstats
path: root/src/input/killX11Handler.cpp
blob: 8fa8c249ed835f4f2e7db20c6e2dac2c5290ab82 (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
/*
 # Copyright (c) 2009 - OpenSLX Project, Computer Center University of Freiburg
 #
 # This program is free software distributed under the GPL version 2.
 # See http://openslx.org/COPYING
 #
 # If you have any feedback please consult http://openslx.org/feedback and
 # send your suggestions, praise, or complaints to feedback@openslx.org
 #
 # General information about OpenSLX can be found at http://openslx.org/
 # --------------------------------------------------------------------------
 # killX11Handler.h
 #  - Kill the X11 Server - implementation
 # --------------------------------------------------------------------------
 */

#include <sys/types.h>
#include <signal.h>
#include <cerrno>
#include <QDir>
#include <QFileInfo>
#include <QStringList>
#include "pvsCheckPrivileges.h"
#include "killX11Handler.h"

using namespace std;

void KillX11Handler::doHandle(InputEvent const&, InputEventContext const* ctx)
{
	// Find out which display device is used:
	QString displayDevice = PVSCheckPrivileges::instance()->getX11DisplayDevice(ctx);
	QString displayDeviceAbs = QFileInfo(displayDevice).canonicalFilePath();

	if(displayDevice.isNull())
	{
		qWarning("Can not kill X server for %d,%d,%d: No Display Device", ctx->senderPid(), ctx->senderUid(), ctx->senderGid());
		return;
	}

	QList<pid_t> pids;

	// Find all processes that have it opened:
	QDir proc("/proc");
	QFileInfoList entries = proc.entryInfoList(QDir::Dirs | QDir::NoDotAndDotDot);
	foreach(QFileInfo fi, entries)
	{
		// We are only interested in numerical ids:
		bool ok;
		pid_t pid = fi.fileName().toUInt(&ok);
		if(!ok)
			continue;

		// We have a pid. Now check open files:
		QDir fds(QString("/proc/%1/fd").arg(pid));
		qDebug("Searching for X server in %s", fds.absolutePath().toLocal8Bit().constData());
		QFileInfoList fdfiles = fds.entryInfoList(QDir::Files);
		foreach(QFileInfo fdfile, fdfiles)
		{
			qDebug("  Looking for terminal in %s", fdfile.absoluteFilePath().toLocal8Bit().constData());
			QFileInfo fdTarget(fdfile.readLink());
			if(fdTarget.canonicalFilePath() == displayDeviceAbs)
			{
				qDebug("  ... found");
				pids << pid;
			}
		}
	}

	// If everything is well, we have exactly one pid:
	if(pids.size() != 1)
	{
		QStringList pidStrs;
		foreach(pid_t pid, pids)
		{
			pidStrs << QString::number(pid);
		}

		qWarning("Display device %s is open by multiple or zero processes (%s). We don't know which is X. Aborting.",
				displayDeviceAbs.toLocal8Bit().constData(),
				pidStrs.join(", ").toLocal8Bit().constData());
		return;
	}

	// We found the PID for the X server. Now kill it.
	QString exe = QFileInfo(QString("/proc/%1/exe").arg(pids[0])).readLink();
	qDebug("Killing X server, PID %d, exe name %s with SIGTERM", pids[0], exe.toLocal8Bit().constData());

	kill(pids[0], SIGTERM);
}