Version: 2.1.2 (using KDE KDE 3.5.4) Installed from: Mandriva RPMs OS: Linux If ktorrent is started a second time by the same user, but using a different $DISPLAY (e.g. through a ssh connection, vnc, etc), ktorrent reports that the ports are in use and keeps its normal execution path, trying to read/write on files used by the first instance and eventually crashing and/or corrupting files. To reproduce: $ ktorrent $ export DISPLAY=localhost:0.0 $ ktorrent (assuming your X server is configured to listen to tcp connections... otherwise you can use ssh -X localhost to get a new $DISPLAY env)
KTorrent uses KUniqueApplication to achieve the only one instance functionality, so this is a bug in kdelibs.
I'm afraid it's not. KUniqueApp only guarantees one instance per KDE session - I'll make sure this is added to the documentation for KDE4
To me it would make more sense that this functionality would be implemented in KUniqueApplication, KTorrent is probably not the only app which will have problems under these circumstances. Anyway, it seems that we will have to come up with something ourselves.
SVN commit 659769 by guisson: Make sure only one instance of KT can run for each user (regardless of the current $DISPLAY), this fixes bug 143791. This is implemented by a hidden lock file in the users's home directory. BUG: 143791 M +19 -28 ktorrentapp.cpp M +45 -0 main.cpp --- trunk/extragear/network/ktorrent/apps/ktorrent/ktorrentapp.cpp #659768:659769 @@ -45,40 +45,31 @@ if (!dcopClient()->isRegistered() ) dcopClient()->registerAs(name(), false); - // see if we are starting with session management -/* if (restoringSession()) + KCmdLineArgs *args = KCmdLineArgs::parsedArgs(); + bt::Globals::instance().setDebugMode(args->isSet("debug")); + + QString data_dir = KGlobal::dirs()->saveLocation("data","ktorrent"); + if (!data_dir.endsWith(bt::DirSeparator())) + data_dir += bt::DirSeparator(); + bt::Globals::instance().initLog(data_dir + "log"); + + if (!mainWidget()) { - RESTORE(KTorrent); + KTorrent *widget = new KTorrent(); + setMainWidget(widget); } - else*/ - { - // no session.. just start up normally - KCmdLineArgs *args = KCmdLineArgs::parsedArgs(); - bt::Globals::instance().setDebugMode(args->isSet("debug")); + else + KStartupInfo::setNewStartupId( mainWidget(), kapp->startupId()); - QString data_dir = KGlobal::dirs()->saveLocation("data","ktorrent"); - if (!data_dir.endsWith(bt::DirSeparator())) - data_dir += bt::DirSeparator(); - bt::Globals::instance().initLog(data_dir + "log"); - if (!mainWidget()) - { - KTorrent *widget = new KTorrent(); - setMainWidget(widget); - } - else - KStartupInfo::setNewStartupId( mainWidget(), kapp->startupId()); + KTorrent *widget = ::qt_cast<KTorrent*>( mainWidget() ); - - KTorrent *widget = ::qt_cast<KTorrent*>( mainWidget() ); - - for (int i = 0; i < args->count(); i++) - { - widget->load(args->url(i)); - } - - args->clear(); + for (int i = 0; i < args->count(); i++) + { + widget->load(args->url(i)); } + + args->clear(); return 0; } --- trunk/extragear/network/ktorrent/apps/ktorrent/main.cpp #659768:659769 @@ -34,14 +34,25 @@ #include <qapplication.h> #include <stdio.h> #include <stdlib.h> +#include <unistd.h> +#include <sys/types.h> +#include <sys/stat.h> +#include <sys/file.h> +#include <errno.h> +#include <fcntl.h> #include <util/error.h> #include <util/log.h> #include <torrent/globals.h> +#include <util/fileops.h> #include <ktversion.h> +#include <functions.h> +#include <qfile.h> +#include <qdir.h> using namespace bt; + void StupidWarningMessagesFromQt( QtMsgType type, const char *msg ) { switch ( type ) @@ -60,11 +71,38 @@ } + static const char description[] = I18N_NOOP("A BitTorrent program for KDE"); +bool GrabPIDLock() +{ + // open the PID file in the users ktorrent directory and attempt to lock it + QString pid_file = QDir::homeDirPath() + "/.ktorrent.lock"; + + int fd = open(QFile::encodeName(pid_file),O_RDWR|O_CREAT,0640); + if (fd < 0) + { + fprintf(stderr,"Failed to open KT lock file %s : %s\n",pid_file.ascii(),strerror(errno)); + return false; + } + if (lockf(fd,F_TLOCK,0)<0) + { + fprintf(stderr,"Failed to get lock on %s : %s\n",pid_file.ascii(),strerror(errno)); + return false; + } + + char str[20]; + sprintf(str,"%d\n",getpid()); + write(fd,str,strlen(str)); /* record pid to lockfile */ + + // leave file open, so nobody else can lock it until KT exists + return true; +} + + static KCmdLineOptions options[] = { { "debug", I18N_NOOP("Debug mode"), 0 }, @@ -120,6 +158,13 @@ fprintf(stderr, "ktorrent is already running!\n"); return 0; } + + // need to grab lock after the fork call in start, otherwise this will not work properly + if (!GrabPIDLock()) + { + fprintf(stderr, "ktorrent is already running!\n"); + return 0; + } try {