diff --git a/src/private/standarddirs.cpp b/src/private/standarddirs.cpp --- a/src/private/standarddirs.cpp +++ b/src/private/standarddirs.cpp @@ -110,6 +110,8 @@ fullPath = QStandardPaths::writableLocation(QStandardPaths::GenericConfigLocation) + fullRelPath; } else if (qstrncmp(resource, "data", 4) == 0) { fullPath = QStandardPaths::writableLocation(QStandardPaths::GenericDataLocation) + fullRelPath; + } else if (qstrncmp(resource, "runtime", 7) == 0) { + fullPath = QStandardPaths::writableLocation(QStandardPaths::RuntimeLocation) + fullRelPath; } else { qt_assert_x(__FUNCTION__, "Invalid resource type", __FILE__, __LINE__); return {}; diff --git a/src/server/akonadi.cpp b/src/server/akonadi.cpp --- a/src/server/akonadi.cpp +++ b/src/server/akonadi.cpp @@ -142,16 +142,19 @@ connectionSettings.setValue(QStringLiteral("Notifications/Method"), QStringLiteral("NamedPipe")); connectionSettings.setValue(QStringLiteral("Notifications/NamedPipe"), ntfPipe); #else - const QString socketDir = Utils::preferredSocketDirectory(StandardDirs::saveDir("data")); - const QString cmdSocketFile = socketDir % QStringLiteral("/akonadiserver-cmd.socket"); + const QString cmdSocketName = QStringLiteral("akonadiserver-cmd.socket"); + const QString ntfSocketName = QStringLiteral("akonadiserver-ntf.socket"); + const QString socketDir = Utils::preferredSocketDirectory(StandardDirs::saveDir("data"), + qMax(cmdSocketName.length(), ntfSocketName.length())); + const QString cmdSocketFile = socketDir % QLatin1Char('/') % cmdSocketName; QFile::remove(cmdSocketFile); if (!mCmdServer->listen(cmdSocketFile)) { qCCritical(AKONADISERVER_LOG) << "Unable to listen on Unix socket" << cmdSocketFile << ":" << mCmdServer->errorString(); quit(); return false; } - const QString ntfSocketFile = socketDir % QStringLiteral("/akonadiserver-ntf.socket"); + const QString ntfSocketFile = socketDir % QLatin1Char('/') % ntfSocketName; QFile::remove(ntfSocketFile); if (!mNtfServer->listen(ntfSocketFile)) { qCCritical(AKONADISERVER_LOG) << "Unable to listen on Unix socket" << ntfSocketFile << ":" << mNtfServer->errorString(); diff --git a/src/server/storage/dbconfigmysql.cpp b/src/server/storage/dbconfigmysql.cpp --- a/src/server/storage/dbconfigmysql.cpp +++ b/src/server/storage/dbconfigmysql.cpp @@ -42,6 +42,8 @@ #define MYSQL_VERSION_CHECK(major, minor, patch) ((major << 16) | (minor << 8) | patch) +static const QString s_mysqlSocketFileName = QStringLiteral("mysql.socket"); + DbConfigMysql::DbConfigMysql() : mInternalServer(true) , mDatabaseProcess(nullptr) @@ -86,7 +88,8 @@ QString defaultCleanShutdownCommand; #ifndef Q_OS_WIN - const QString socketDirectory = Utils::preferredSocketDirectory(StandardDirs::saveDir("data", QStringLiteral("db_misc"))); + const QString socketDirectory = Utils::preferredSocketDirectory(StandardDirs::saveDir("data", QStringLiteral("db_misc")), + s_mysqlSocketFileName.length()); #endif const bool defaultInternalServer = true; @@ -102,8 +105,8 @@ const QString mysqladminPath = findExecutable(QStringLiteral("mysqladmin")); if (!mysqladminPath.isEmpty()) { #ifndef Q_OS_WIN - defaultCleanShutdownCommand = QStringLiteral("%1 --defaults-file=%2/mysql.conf --socket=%3/mysql.socket shutdown") - .arg(mysqladminPath, StandardDirs::saveDir("data"), socketDirectory); + defaultCleanShutdownCommand = QStringLiteral("%1 --defaults-file=%2/mysql.conf --socket=%3/%4 shutdown") + .arg(mysqladminPath, StandardDirs::saveDir("data"), socketDirectory, s_mysqlSocketFileName); #else defaultCleanShutdownCommand = QString::fromLatin1("%1 shutdown --shared-memory").arg(mysqladminPath); #endif @@ -118,7 +121,7 @@ mInternalServer = settings.value(QStringLiteral("QMYSQL/StartServer"), defaultInternalServer).toBool(); #ifndef Q_OS_WIN if (mInternalServer) { - defaultOptions = QStringLiteral("UNIX_SOCKET=%1/mysql.socket").arg(socketDirectory); + defaultOptions = QStringLiteral("UNIX_SOCKET=%1/%2").arg(socketDirectory, s_mysqlSocketFileName); } #endif @@ -200,8 +203,9 @@ const QString akDir = StandardDirs::saveDir("data"); const QString dataDir = StandardDirs::saveDir("data", QStringLiteral("db_data")); #ifndef Q_OS_WIN - const QString socketDirectory = Utils::preferredSocketDirectory(StandardDirs::saveDir("data", QStringLiteral("db_misc"))); - const QString socketFile = QStringLiteral("%1/mysql.socket").arg(socketDirectory); + const QString socketDirectory = Utils::preferredSocketDirectory(StandardDirs::saveDir("data", QStringLiteral("db_misc")), + s_mysqlSocketFileName.length()); + const QString socketFile = QStringLiteral("%1/%2").arg(socketDirectory, s_mysqlSocketFileName); const QString pidFileName = QStringLiteral("%1/mysql.pid").arg(socketDirectory); #endif @@ -302,7 +306,7 @@ return false; } - // If mysql.socket file exists, check if also the server process is still running, + // If mysql socket file exists, check if also the server process is still running, // else we can safely remove the socket file (cleanup after a system crash, etc.) QFile pidFile(pidFileName); if (QFile::exists(socketFile) && pidFile.open(QIODevice::ReadOnly)) { @@ -348,7 +352,7 @@ #endif #ifndef Q_OS_WIN - // If mysql.socket file does not exists, then we must start the server, + // If mysql socket file does not exists, then we must start the server, // otherwise we reconnect to it if (!QFile::exists(socketFile)) { // move mysql error log file out of the way @@ -403,7 +407,7 @@ QThread::msleep(100); } } else { - qCDebug(AKONADISERVER_LOG) << "Found mysql.socket file, reconnecting to the database"; + qCDebug(AKONADISERVER_LOG) << "Found " << qPrintable(s_mysqlSocketFileName) << " file, reconnecting to the database"; } #endif @@ -442,7 +446,7 @@ QStringLiteral("--check-upgrade"), QStringLiteral("--auto-repair"), #ifndef Q_OS_WIN - QStringLiteral("--socket=%1/mysql.socket").arg(socketDirectory), + QStringLiteral("--socket=%1/%2").arg(socketDirectory, s_mysqlSocketFileName), #endif mDatabaseName }); @@ -514,8 +518,9 @@ #ifndef Q_OS_WIN // when the server stopped unexpectedly, make sure to remove the stale socket file since otherwise // it can not be started again - const QString socketDirectory = Utils::preferredSocketDirectory(StandardDirs::saveDir("data", QStringLiteral("db_misc"))); - const QString socketFile = QStringLiteral("%1/mysql.socket").arg(socketDirectory); + const QString socketDirectory = Utils::preferredSocketDirectory(StandardDirs::saveDir("data", QStringLiteral("db_misc")), + s_mysqlSocketFileName.length()); + const QString socketFile = QStringLiteral("%1/%2").arg(socketDirectory, s_mysqlSocketFileName); QFile::remove(socketFile); #endif diff --git a/src/server/utils.h b/src/server/utils.h --- a/src/server/utils.h +++ b/src/server/utils.h @@ -99,8 +99,10 @@ /** * Returns the socket @p directory that is passed to this method or the one * the user has overwritten via the config file. + * The passed @p fnLengthHint will also ensure the absolute file path length of the + * directory + separator + hint would not overflow the system limitation. */ -QString preferredSocketDirectory(const QString &directory); +QString preferredSocketDirectory(const QString &directory, int fnLengthHint = -1); /** * Returns name of filesystem that @p directory is stored on. This diff --git a/src/server/utils.cpp b/src/server/utils.cpp --- a/src/server/utils.cpp +++ b/src/server/utils.cpp @@ -21,6 +21,7 @@ #include "utils.h" #include "akonadiserver_debug.h" +#include "instance_p.h" #include @@ -32,13 +33,13 @@ #if !defined(Q_OS_WIN) #include #include +#include #include -#include #include static QString akonadiSocketDirectory(); static bool checkSocketDirectory(const QString &path); -static bool createSocketDirectory(const QString &link, const QString &tmpl); +static bool createSocketDirectory(const QString &link, const QString &identifier); #endif #ifdef Q_OS_LINUX @@ -51,7 +52,7 @@ using namespace Akonadi; using namespace Akonadi::Server; -QString Utils::preferredSocketDirectory(const QString &defaultDirectory) +QString Utils::preferredSocketDirectory(const QString &defaultDirectory, int fnLengthHint) { const QString serverConfigFile = StandardDirs::serverConfigFile(StandardDirs::ReadWrite); const QSettings serverSettings(serverConfigFile, QSettings::IniFormat); @@ -87,6 +88,10 @@ if (!dirInfo.exists()) { QDir::home().mkpath(dirInfo.absoluteFilePath()); } + + if (socketDir.length() + 1 + fnLengthHint >= static_cast(sizeof(sockaddr_un::sun_path))) { + qCCritical(AKONADISERVER_LOG) << "akonadiSocketDirectory() length is too long to be used by the system."; + } #endif return socketDir; } @@ -101,25 +106,14 @@ return QString(); } - const uid_t uid = getuid(); - const struct passwd *pw_ent = getpwuid(uid); - if (!pw_ent) { - qCCritical(AKONADISERVER_LOG) << "Could not get passwd entry for user id" << uid; - return QString(); - } - - const QString link = StandardDirs::saveDir("data") + QLatin1Char('/') + QLatin1String("socket-") + hostname; - QString tmpl = QLatin1String("akonadi-") + QString::fromLocal8Bit(pw_ent->pw_name) + QLatin1String(".XXXXXX"); - - // Workaround for QLocalServer encoding bug - // basically replace non-latin characters - tmpl = QString::fromLatin1(tmpl.toLatin1()); + const QString identifier = Instance::hasIdentifier() ? Instance::identifier() : QLatin1String("default"); + const QString link = StandardDirs::saveDir("data") + QStringLiteral("/socket-%1-%2").arg(hostname, identifier); if (checkSocketDirectory(link)) { return QFileInfo(link).symLinkTarget(); } - if (createSocketDirectory(link, tmpl)) { + if (createSocketDirectory(link, identifier)) { return QFileInfo(link).symLinkTarget(); } @@ -150,19 +144,15 @@ return true; } -static bool createSocketDirectory(const QString &link, const QString &tmpl) +static bool createSocketDirectory(const QString &link, const QString &identifier) { - QString directory = QStringLiteral("%1%2%3").arg(QDir::tempPath()).arg(QDir::separator()).arg(tmpl); + const QString directory = QStringLiteral("%1/%2").arg(StandardDirs::saveDir("runtime"), identifier); - QByteArray directoryString = directory.toLocal8Bit(); - - if (!mkdtemp(directoryString.data())) { - qCCritical(AKONADISERVER_LOG) << "Creating socket directory with template" << directoryString << "failed:" << strerror(errno); + if (!QDir().mkpath(directory)) { + qCCritical(AKONADISERVER_LOG) << "Creating socket directory with name" << directory << "failed:" << strerror(errno); return false; } - directory = QString::fromLocal8Bit(directoryString); - QFile::remove(link); if (!QFile::link(directory, link)) { @@ -177,6 +167,7 @@ QString Utils::getDirectoryFileSystem(const QString &directory) { #ifndef Q_OS_LINUX + Q_UNUSED(directory); return QString(); #else QString bestMatchPath;