8#include "xwayland_logging.h"
10#include <QCoreApplication>
16#include <sys/socket.h>
34 const sockaddr *
data()
const;
43 const QByteArray encodedSocketPath = QFile::encodeName(socketPath);
45 int byteCount = offsetof(sockaddr_un, sun_path) + encodedSocketPath.size() + 1;
46 m_buffer.resize(byteCount);
48 sockaddr_un *address =
reinterpret_cast<sockaddr_un *
>(m_buffer.data());
49 address->sun_family = AF_UNIX;
52 memcpy(address->sun_path, encodedSocketPath.data(), encodedSocketPath.size());
53 address->sun_path[encodedSocketPath.size()] =
'\0';
56 *address->sun_path =
'\0';
57 memcpy(address->sun_path + 1, encodedSocketPath.data(), encodedSocketPath.size());
63 return reinterpret_cast<const sockaddr *
>(m_buffer.data());
68 return m_buffer.size();
71static QString lockFileNameForDisplay(
int display)
73 return QStringLiteral(
"/tmp/.X%1-lock").arg(display);
76static QString socketFileNameForDisplay(
int display)
78 return QStringLiteral(
"/tmp/.X11-unix/X%1").arg(display);
81static bool tryLockFile(
const QString &lockFileName)
83 for (
int attempt = 0; attempt < 3; ++attempt) {
84 QFile lockFile(lockFileName);
85 if (lockFile.open(QFile::WriteOnly | QFile::NewOnly)) {
87 snprintf(buffer,
sizeof(buffer),
"%10lld\n", QCoreApplication::applicationPid());
88 if (lockFile.write(buffer,
sizeof(buffer) - 1) !=
sizeof(buffer) - 1) {
89 qCWarning(KWIN_XWL) <<
"Failed to write pid to lock file:" << lockFile.errorString();
94 }
else if (lockFile.open(QFile::ReadOnly)) {
95 const int lockPid = lockFile.readLine().trimmed().toInt();
99 if (kill(lockPid, 0) < 0 && errno == ESRCH) {
111 const UnixSocketAddress socketAddress(filePath,
type);
113 int socketFlags = SOCK_STREAM;
115 socketFlags |= SOCK_CLOEXEC;
117 int fileDescriptor = socket(AF_UNIX, socketFlags, 0);
118 if (fileDescriptor == -1) {
122 if (bind(fileDescriptor, socketAddress.data(), socketAddress.size()) == -1) {
123 close(fileDescriptor);
127 if (listen(fileDescriptor, 1) == -1) {
128 close(fileDescriptor);
132 return fileDescriptor;
135static bool checkSocketsDirectory()
138 const char *path =
"/tmp/.X11-unix";
140 if (lstat(path, &info) != 0) {
141 if (errno == ENOENT) {
142 qCWarning(KWIN_XWL) << path <<
"does not exist. Please check your installation";
146 qCWarning(KWIN_XWL,
"Failed to stat %s: %s", path, strerror(errno));
150 if (!S_ISDIR(info.st_mode)) {
151 qCWarning(KWIN_XWL) << path <<
"is not a directory. Broken system?";
154 if (info.st_uid != 0 && info.st_uid != getuid()) {
155 qCWarning(KWIN_XWL) << path <<
"is not owned by root or us";
158 if (!(info.st_mode & S_ISVTX)) {
159 qCWarning(KWIN_XWL) << path <<
"has no sticky bit on. Your system might be compromised!";
168 if (!checkSocketsDirectory()) {
173 const QString socketFilePath = socketFileNameForDisplay(
display);
174 const QString lockFilePath = lockFileNameForDisplay(
display);
176 if (!tryLockFile(lockFilePath)) {
183 close(fileDescriptor);
187 QFile::remove(socketFilePath);
189 if (unixFileDescriptor == -1) {
190 QFile::remove(lockFilePath);
195#if defined(Q_OS_LINUX)
197 if (abstractFileDescriptor == -1) {
198 QFile::remove(lockFilePath);
199 QFile::remove(socketFilePath);
206 socketCleanup.dismiss();
208 m_socketFilePath = socketFilePath;
209 m_lockFilePath = lockFilePath;
214 qCWarning(KWIN_XWL) <<
"Failed to find free X11 connection socket";
219 for (
const int &fileDescriptor : std::as_const(m_fileDescriptors)) {
220 close(fileDescriptor);
222 if (!m_socketFilePath.isEmpty()) {
223 QFile::remove(m_socketFilePath);
225 if (!m_lockFilePath.isEmpty()) {
226 QFile::remove(m_lockFilePath);
232 return m_display != -1;
237 return m_fileDescriptors;
247 return ":" + QString::number(m_display);
const sockaddr * data() const
UnixSocketAddress(const QString &socketPath, Type type)
XwaylandSocket(OperationMode operationMode)
QList< int > fileDescriptors() const