[Date Prev][Date Next] [Thread Prev][Thread Next] [Date Index] [Thread Index]

Bug#545139: akonadi-server: not possible to create socket in AFS $HOME



Hi,

as discussed on IRC, I backported the upstream patch for this bug.

The functions in socketdir.cpp are now identical to upstream's, just
moved from utils.cpp to socketdir.cpp (as I was using this in the
earlier patch and utils.cpp is not present in Debian's version of
Akonadi anyway).

The upstream fix 1fa22c55fd98f29321b943605466ef4d4640de53 is included as
well, as per my original patch.

In addition, several places had to be changed to use the
preferredSocketDirectory function.

Upstream commit: e4affdfc2922efc10b647939fd4e068c02e256eb

Regards,
Ansgar

From: Ansgar Burchardt <ansgar@debian.org>
Date: Mon, 29 Nov 2010 12:40:18 +0100
Subject: Move sockets away from $HOME
Bug-Debian: http://bugs.debian.org/545139
Bug: https://bugs.kde.org/show_bug.cgi?id=179006

Move directories used for sockets to /tmp, using a symlink (that includes the
hostname) to remember where it is located.

Based on upstream commit e4affdfc2922efc10b647939fd4e068c02e256eb,
includes the fix 1fa22c55fd98f29321b943605466ef4d4640de53 as well.

--- akonadi-1.3.1.orig/server/CMakeLists.txt
+++ akonadi-1.3.1/server/CMakeLists.txt
@@ -59,6 +59,7 @@
 set(libakonadiprivate_SRCS
   ${AKONADI_SHARED_SOURCES}
   src/akonadi.cpp
+  src/socketdir.cpp
   src/akonadiconnection.cpp
   src/handler.cpp
   src/handlerhelper.cpp
--- akonadi-1.3.1.orig/server/src/akonadi.cpp
+++ akonadi-1.3.1/server/src/akonadi.cpp
@@ -34,6 +34,7 @@
 #include "debuginterface.h"
 #include "storage/itemretrievalthread.h"
 #include "preprocessormanager.h"
+#include "socketdir.h"
 
 #include "libs/xdgbasedirs_p.h"
 #include "libs/protocol_p.h"
@@ -84,13 +85,7 @@
     connectionSettings.setValue( QLatin1String( "Data/Method" ), QLatin1String( "NamedPipe" ) );
     connectionSettings.setValue( QLatin1String( "Data/NamedPipe" ), namedPipe );
 #else
-    const QString defaultSocketDir = XdgBaseDirs::saveDir( "data", QLatin1String( "akonadi" ) );
-    QString socketDir = settings.value( QLatin1String( "Connection/SocketDirectory" ), defaultSocketDir ).toString();
-    if ( socketDir[0] != QLatin1Char( '/' ) ) {
-      QDir::home().mkdir( socketDir );
-      socketDir = QDir::homePath() + QLatin1Char( '/' ) + socketDir;
-    }
-
+    QString socketDir = preferredSocketDirectory( XdgBaseDirs::saveDir( "data", QLatin1String( "akonadi" ) ) );
     const QString socketFile = socketDir + QLatin1String( "/akonadiserver.socket" );
     unlink( socketFile.toUtf8().constData() );
     if ( !listen( socketFile ) )
@@ -202,8 +197,7 @@
 
 #ifndef Q_OS_WIN
     QSettings connectionSettings( connectionSettingsFile, QSettings::IniFormat );
-    const QString defaultSocketDir = XdgBaseDirs::saveDir( "data", QLatin1String( "akonadi" ) );
-    const QString socketDir = settings.value( QLatin1String( "Connection/SocketDirectory" ), defaultSocketDir ).toString();
+    const QString socketDir = preferredSocketDirectory( XdgBaseDirs::saveDir( "data", QLatin1String( "akonadi" ) ) );
 
     if ( !QDir::home().remove( socketDir + QLatin1String( "/akonadiserver.socket" ) ) )
         akError() << "Failed to remove Unix socket";
@@ -261,7 +255,7 @@
 void AkonadiServer::startPostgresqlDatabaseProcess()
 {
   const QString dataDir = XdgBaseDirs::saveDir( "data", QLatin1String( "akonadi/db_data" ) );
-  const QString socketDir = XdgBaseDirs::saveDir( "data", QLatin1String( "akonadi/db_misc" ) );
+  const QString socketDir = preferredSocketDirectory( XdgBaseDirs::saveDir( "data", QLatin1String( "akonadi/db_misc" ) ) );
 
   if ( !QFile::exists( QString::fromLatin1( "%1/PG_VERSION" ).arg( dataDir ) ) ) {
     // postgre data directory not initialized yet, so call initdb on it
@@ -371,7 +365,7 @@
 
   const QString dataDir = XdgBaseDirs::saveDir( "data", QLatin1String( "akonadi/db_data" ) );
   const QString akDir   = XdgBaseDirs::saveDir( "data", QLatin1String( "akonadi/" ) );
-  const QString miscDir = XdgBaseDirs::saveDir( "data", QLatin1String( "akonadi/db_misc" ) );
+  const QString miscDir = preferredSocketDirectory( XdgBaseDirs::saveDir( "data", QLatin1String( "akonadi/db_misc" ) ) );
   const QString fileDataDir = XdgBaseDirs::saveDir( "data", QLatin1String( "akonadi/file_db_data" ) );
 
   // generate config file
--- /dev/null
+++ akonadi-1.3.1/server/src/socketdir.cpp
@@ -0,0 +1,127 @@
+#include "socketdir.h"
+
+#include "libs/xdgbasedirs_p.h"
+
+#include <QtCore/QDebug>
+#include <QtCore/QDir>
+#include <QtCore/QFileInfo>
+#include <QtCore/QSettings>
+#include <QtNetwork/QHostInfo>
+
+#include <cerrno>
+#include <cstdlib>
+#include <pwd.h>
+#include <sys/types.h>
+#include <unistd.h>
+
+static QString akonadiSocketDirectory();
+static bool checkSocketDirectory( const QString &path );
+static bool createSocketDirectory( const QString &link, const QString &tmpl );
+
+using namespace Akonadi;
+
+QString Akonadi::preferredSocketDirectory( const QString &defaultDirectory )
+{
+  const QString serverConfigFile = XdgBaseDirs::akonadiServerConfigFile( XdgBaseDirs::ReadWrite );
+  const QSettings serverSettings( serverConfigFile, QSettings::IniFormat );
+
+#if defined(Q_OS_WINCE) || defined(Q_OS_WIN)
+  const QString socketDir = serverSettings.value( QLatin1String( "Connection/SocketDirectory" ), defaultDirectory ).toString();
+#else
+  QString socketDir = defaultDirectory;
+  if ( !serverSettings.contains( QLatin1String( "Connection/SocketDirectory" ) ) ) {
+    // if no socket directory is defined, use the symlinked from /tmp
+    socketDir = akonadiSocketDirectory();
+
+    if ( socketDir.isEmpty() ) // if that does not work, fall back on default
+      socketDir = defaultDirectory;
+  } else {
+    socketDir = serverSettings.value( QLatin1String( "Connection/SocketDirectory" ), defaultDirectory ).toString();
+  }
+
+  const QString userName = QString::fromLocal8Bit( qgetenv( "USER" ) );
+  if ( socketDir.contains( QLatin1String( "$USER" ) ) && !userName.isEmpty() )
+    socketDir.replace( QLatin1String( "$USER" ), userName );
+
+  if ( socketDir[0] != QLatin1Char( '/' ) ) {
+    QDir::home().mkdir( socketDir );
+    socketDir = QDir::homePath() + QLatin1Char( '/' ) + socketDir;
+  }
+
+  QFileInfo dirInfo( socketDir );
+  if ( !dirInfo.exists() )
+    QDir::home().mkpath( dirInfo.absoluteFilePath() );
+#endif
+  return socketDir;
+}
+
+QString akonadiSocketDirectory()
+{
+  const QString hostname = QHostInfo::localHostName();
+
+  if ( hostname.isEmpty() ) {
+    qCritical() << "QHostInfo::localHostName() failed";
+    return QString();
+  }
+
+  const uid_t uid = getuid();
+  const struct passwd *pw_ent = getpwuid( uid );
+  if ( !pw_ent ) {
+    qCritical() << "Could not get passwd entry for user id" << uid;
+    return QString();
+  }
+
+  const QString link = XdgBaseDirs::saveDir( "data", QLatin1String( "akonadi" ) ) + QLatin1Char( '/' ) + QLatin1String( "socket-" ) + hostname;
+  const QString tmpl = QLatin1String( "akonadi-" ) + QLatin1String( pw_ent->pw_name ) + QLatin1String( ".XXXXXX" );
+
+  if ( checkSocketDirectory( link ) )
+    return link;
+
+  if ( createSocketDirectory( link, tmpl ) )
+    return link;
+
+  qCritical() << "Could not create socket directory for Akonadi.";
+  return QString();
+}
+
+static bool checkSocketDirectory( const QString &path )
+{
+  QFileInfo info( path );
+
+  if ( !info.exists() )
+    return false;
+
+  if ( info.isSymLink() )
+    info = QFileInfo( info.symLinkTarget() );
+
+  if ( !info.isDir() )
+    return false;
+
+  if ( info.ownerId() != getuid() )
+    return false;
+
+  return true;
+}
+
+static bool createSocketDirectory( const QString &link, const QString &tmpl )
+{
+  QString directory = QString::fromLatin1( "%1%2%3" ).arg( QDir::tempPath() ).arg( QDir::separator() ).arg( tmpl );
+
+  QByteArray directoryString = directory.toLocal8Bit().data();
+
+  if ( !mkdtemp( directoryString.data() ) ) {
+    qCritical() << "Creating socket directory with template" << directoryString << "failed:" << strerror( errno );
+    return false;
+  }
+
+  directory = QString::fromLocal8Bit( directoryString );
+
+  QFile::remove( link );
+
+  if ( !QFile::link( directory, link ) ) {
+    qCritical() << "Creating symlink from" << directory << "to" << link << "failed";
+    return false;
+  }
+
+  return true;
+}
--- /dev/null
+++ akonadi-1.3.1/server/src/socketdir.h
@@ -0,0 +1,10 @@
+#ifndef AKONADI_SOCKETDIR_H
+#define AKONADI_SOCKETDIR_H
+
+#include <QtCore/QString>
+
+namespace Akonadi {
+  QString preferredSocketDirectory(const QString &defaultDirectory);
+}
+
+#endif
--- akonadi-1.3.1.orig/server/src/storage/dbconfig.cpp
+++ akonadi-1.3.1/server/src/storage/dbconfig.cpp
@@ -20,6 +20,7 @@
 #include "dbconfig.h"
 #include "akdebug.h"
 #include "../../libs/xdgbasedirs_p.h"
+#include "../socketdir.h"
 
 #include <QDir>
 #include <QFile>
@@ -97,11 +98,11 @@
         if ( !mysqladminPath.isEmpty() ) {
           defaultCleanShutdownCommand = QString::fromLatin1("%1 shutdown --socket=%2/mysql.socket")
                                             .arg(mysqladminPath)
-                                            .arg(XdgBaseDirs::saveDir( "data", QLatin1String( "akonadi/db_misc" ) ) );
+                                            .arg( preferredSocketDirectory( XdgBaseDirs::saveDir( "data", QLatin1String( "akonadi/db_misc" ) ) ) );
         }
         mInternalServer = settings.value( QLatin1String("QMYSQL/StartServer"), defaultInternalServer ).toBool();
         if ( mInternalServer ) {
-          const QString miscDir = XdgBaseDirs::saveDir( "data", QLatin1String( "akonadi/db_misc" ) );
+          const QString miscDir = preferredSocketDirectory( XdgBaseDirs::saveDir( "data", QLatin1String( "akonadi/db_misc" ) ) );
           defaultOptions = QString::fromLatin1( "UNIX_SOCKET=%1/mysql.socket" ).arg( miscDir );
         }
       } else if ( mDriverName == QLatin1String("QMYSQL_EMBEDDED") ) {
@@ -142,7 +143,7 @@
 
       // verify settings and apply permanent changes (written out below)
       if ( mDriverName == QLatin1String( "QMYSQL" ) ) {
-        if ( mInternalServer && mConnectionOptions.isEmpty() )
+        if ( mInternalServer /* && mConnectionOptions.isEmpty() */ )
           mConnectionOptions = defaultOptions;
         if ( mInternalServer && (mServerPath.isEmpty() || !QFile::exists(mServerPath) ) )
           mServerPath = defaultServerPath;

Reply to: