kinit: klauncher and KCrash rewrite

much simpler and easier to maintain, also it will be proper D-Bus
service now with no sockets, process title hack and whatnot. KCrash
and startkde script (in kde-workspace repo) have to be adjusted for
it tho

note that the internal KIO scheduler already has the functionality to
put slaves on hold but now they will be started as detached process.
eventually they may become plugins (they are loaded as such by kioslave
program) without event loop dispatcher

fixes application startup notification (ASN) and cleanup issues

Signed-off-by: Ivailo Monev <xakepa10@gmail.com>
This commit is contained in:
Ivailo Monev 2022-12-03 06:47:32 +02:00
parent e851a35ee5
commit aa6b5ea4f0
27 changed files with 704 additions and 4690 deletions

View file

@ -57,8 +57,6 @@ check_function_exists(fdatasync HAVE_FDATASYNC) # kd
check_function_exists(arc4random_uniform HAVE_ARC4RANDOM_UNIFORM) # kdecore check_function_exists(arc4random_uniform HAVE_ARC4RANDOM_UNIFORM) # kdecore
check_function_exists(sendfile HAVE_SENDFILE) # kioslave check_function_exists(sendfile HAVE_SENDFILE) # kioslave
check_library_exists(socket connect "" HAVE_SOCKET_LIBRARY) # kinit
if (UNIX) if (UNIX)
# for kpty # for kpty
check_include_files("sys/types.h;libutil.h" HAVE_LIBUTIL_H) check_include_files("sys/types.h;libutil.h" HAVE_LIBUTIL_H)

View file

@ -42,6 +42,7 @@
940 kmediaplayer 940 kmediaplayer
1000 kparts 1000 kparts
1209 libplasma 1209 libplasma
1210 klauncher4
7000 kio 7000 kio
7001 kio (KDirWatch) 7001 kio (KDirWatch)
7002 kio (Slave) 7002 kio (Slave)
@ -54,7 +55,6 @@
7011 kdecore (KSycoca) 7011 kdecore (KSycoca)
7014 kdecore (trader) 7014 kdecore (trader)
7015 kio (KAutoMount) 7015 kio (KAutoMount)
7016 kio (KLauncher)
7017 kio (KIOConnection) 7017 kio (KIOConnection)
7019 kio (kioslave) 7019 kio (kioslave)
7020 kded4 7020 kded4

View file

@ -59,18 +59,13 @@ KToolInvocation::~KToolInvocation()
org::kde::KLauncher *KToolInvocation::klauncher() org::kde::KLauncher *KToolInvocation::klauncher()
{ {
if (!QDBusConnection::sessionBus().interface()->isServiceRegistered(QString::fromLatin1("org.kde.klauncher"))) { // If klauncher is not running we need to launch it
kDebug(180) << "klauncher not running... launching kdeinit"; static const QString klauncherInterface = QString::fromLatin1("org.kde.klauncher");
// Try to launch kdeinit. QDBusConnectionInterface* sessionInterface = QDBusConnection::sessionBus().interface();
QString srv = KStandardDirs::findExe(QLatin1String("kdeinit4")); const bool klauncherRunning = sessionInterface->isServiceRegistered(klauncherInterface);
if (srv.isEmpty()) { if (!klauncherRunning) {
kError() << "kdeinit4 not available"; kDebug(7011) << "Launching klauncher";
// NOTE: this will crash users not checking the pointer sessionInterface->startService(klauncherInterface);
return nullptr;
}
QStringList args;
args += QString::fromLatin1("--suicide");
QProcess::execute(srv, args);
} }
return self()->klauncherIface; return self()->klauncherIface;
} }

View file

@ -205,23 +205,23 @@ void KStandarddirsTest::testFindExe()
QSKIP( "kdelibs not installed", SkipAll ); QSKIP( "kdelibs not installed", SkipAll );
// findExe with a result in bin // findExe with a result in bin
const QString kdeinit = KGlobal::dirs()->findExe( "kdeinit4" ); const QString klauncher = KGlobal::dirs()->findExe( "klauncher4" );
QVERIFY( !kdeinit.isEmpty() ); QVERIFY( !klauncher.isEmpty() );
QVERIFY2(kdeinit.endsWith("bin/kdeinit4" EXT, PATH_SENSITIVITY), qPrintable(kdeinit)); QVERIFY2(klauncher.endsWith("bin/klauncher4" EXT, PATH_SENSITIVITY), qPrintable(klauncher));
// Check the "exe" resource too // Check the "exe" resource too
QString kdeinitexe = KGlobal::dirs()->locate( "exe", "kdeinit4" ); QString klauncherexe = KGlobal::dirs()->locate( "exe", "klauncher4" );
QVERIFY2(kdeinitexe.endsWith("bin/kdeinit4" EXT, PATH_SENSITIVITY), qPrintable(kdeinit)); QVERIFY2(klauncherexe.endsWith("bin/klauncher4" EXT, PATH_SENSITIVITY), qPrintable(klauncherexe));
#ifdef Q_OS_UNIX #ifdef Q_OS_UNIX
// findExe with a result in libexec // findExe with a result in libexec
const QString klauncher = KGlobal::dirs()->findExe( "klauncher" ); const QString kioslave = KGlobal::dirs()->findExe( "kioslave" );
QVERIFY( !klauncher.isEmpty() ); QVERIFY( !kioslave.isEmpty() );
QVERIFY( klauncher.endsWith("/klauncher" EXT, PATH_SENSITIVITY ) ); QVERIFY( kioslave.endsWith("/kioslave" EXT, PATH_SENSITIVITY ) );
// locate("exe") with a result in libexec // locate("exe") with a result in libexec
const QString locateExeResult = KGlobal::dirs()->locate("exe", "klauncher"); const QString locateExeResult = KGlobal::dirs()->locate("exe", "kioslave");
QVERIFY(locateExeResult.endsWith("/klauncher" EXT, PATH_SENSITIVITY)); QVERIFY(locateExeResult.endsWith("/kioslave" EXT, PATH_SENSITIVITY));
// findExe with relative path // findExe with relative path
const QString pwd = QDir::currentPath(); const QString pwd = QDir::currentPath();

View file

@ -100,24 +100,6 @@ public Q_SLOTS: // METHODS
return callWithArgumentList(QDBus::Block, QLatin1String("reparseConfiguration"), argumentList); return callWithArgumentList(QDBus::Block, QLatin1String("reparseConfiguration"), argumentList);
} }
inline QDBusReply<qint64> requestHoldSlave(const QString &url, const QString &app_socket)
{
QList<QVariant> argumentList;
argumentList << qVariantFromValue(url) << qVariantFromValue(app_socket);
return callWithArgumentList(QDBus::Block, QLatin1String("requestHoldSlave"), argumentList);
}
inline QDBusReply<qint64> requestSlave(const QString &protocol, const QString &host, const QString &app_socket, QString &error)
{
QList<QVariant> argumentList;
argumentList << qVariantFromValue(protocol) << qVariantFromValue(host) << qVariantFromValue(app_socket);
QDBusMessage reply = callWithArgumentList(QDBus::Block, QLatin1String("requestSlave"), argumentList);
if (reply.type() == QDBusMessage::ReplyMessage && reply.arguments().count() == 2) {
error = qdbus_cast<QString>(reply.arguments().at(1));
}
return reply;
}
inline QDBusReply<void> setLaunchEnv(const QString &name, const QString &value) inline QDBusReply<void> setLaunchEnv(const QString &name, const QString &value)
{ {
QList<QVariant> argumentList; QList<QVariant> argumentList;
@ -151,20 +133,6 @@ public Q_SLOTS: // METHODS
return reply; return reply;
} }
inline QDBusReply<void> waitForSlave(int pid)
{
QList<QVariant> argumentList;
argumentList << qVariantFromValue(pid);
return callWithArgumentList(QDBus::Block, QLatin1String("waitForSlave"), argumentList);
}
inline QDBusReply<bool> checkForHeldSlave(const QString &url)
{
QList<QVariant> argumentList;
argumentList << qVariantFromValue(url);
return callWithArgumentList(QDBus::Block, QLatin1String("checkForHeldSlave"), argumentList);
}
Q_SIGNALS: // SIGNALS Q_SIGNALS: // SIGNALS
void autoStart0Done(); void autoStart0Done();
void autoStart1Done(); void autoStart1Done();

View file

@ -51,12 +51,14 @@
#include <kaboutdata.h> #include <kaboutdata.h>
#include <kcmdlineargs.h> #include <kcmdlineargs.h>
#ifndef KBUILDSYCOCA_NO_KCRASH #ifndef KBUILDSYCOCA_NO_KCRASH
#include <kde_file.h>
#include <kcrash.h> #include <kcrash.h>
#endif #endif
#include <stdlib.h> #include <stdlib.h>
#include <unistd.h> #include <unistd.h>
#include <time.h> #include <time.h>
#include <signal.h>
typedef QHash<QString, KSycocaEntry::Ptr> KBSEntryDict; typedef QHash<QString, KSycocaEntry::Ptr> KBSEntryDict;
typedef QList<KSycocaEntry::List> KSycocaEntryListList; typedef QList<KSycocaEntry::List> KSycocaEntryListList;
@ -81,12 +83,16 @@ static QByteArray g_sycocaPath = 0;
static bool bGlobalDatabase = false; static bool bGlobalDatabase = false;
static bool bMenuTest = false; static bool bMenuTest = false;
void crashHandler(int) void crashHandler(int sig)
{ {
// If we crash while reading sycoca, we delete the database KDE_signal(sig, SIG_DFL);
// in an attempt to recover.
if (!g_sycocaPath.isEmpty()) // If we crash while reading sycoca, we delete the database in an attempt to recover.
unlink(g_sycocaPath.constData()); if (!g_sycocaPath.isEmpty()) {
unlink(g_sycocaPath.constData());
}
::exit(sig);
} }
static QString sycocaPath() static QString sycocaPath()
@ -641,9 +647,7 @@ int main(int argc, char **argv)
KComponentData mainComponent(d); KComponentData mainComponent(d);
#ifndef KBUILDSYCOCA_NO_KCRASH #ifndef KBUILDSYCOCA_NO_KCRASH
KCrash::setCrashHandler(KCrash::defaultCrashHandler); KCrash::setCrashHandler(crashHandler);
KCrash::setEmergencySaveFunction(crashHandler);
KCrash::setApplicationName(QString(appName));
#endif #endif
// force generating of KLocale object. if not, the database will get // force generating of KLocale object. if not, the database will get

View file

@ -79,7 +79,6 @@
#endif #endif
KApplication* KApplication::KApp = 0L; KApplication* KApplication::KApp = 0L;
bool KApplication::loadedByKdeinit = false;
#ifdef Q_WS_X11 #ifdef Q_WS_X11
static Atom atom_DesktopWindow = None; static Atom atom_DesktopWindow = None;
@ -666,12 +665,7 @@ void KApplicationPrivate::parseCommandLine( )
if (qgetenv("KDE_DEBUG").isEmpty() && args->isSet("crashhandler")) if (qgetenv("KDE_DEBUG").isEmpty() && args->isSet("crashhandler"))
{ {
// enable drkonqi // enable drkonqi
KCrash::setDrKonqiEnabled(true); KCrash::setFlags(KCrash::flags() | KCrash::DrKonqi);
}
// Always set the app name, can be usefuls for apps that call setEmergencySaveFunction or enable AutoRestart
KCrash::setApplicationName(args->appName());
if (!QCoreApplication::applicationDirPath().isEmpty()) {
KCrash::setApplicationPath(QCoreApplication::applicationDirPath());
} }
#ifdef Q_WS_X11 #ifdef Q_WS_X11

View file

@ -263,11 +263,6 @@ public:
bool notify( QObject* receiver, QEvent* event ); bool notify( QObject* receiver, QEvent* event );
#endif // Q_WS_X11 #endif // Q_WS_X11
/**
* @internal
*/
static bool loadedByKdeinit;
public Q_SLOTS: public Q_SLOTS:
/** /**
* Updates the last user action timestamp to the given time, or to the current time, * Updates the last user action timestamp to the given time, or to the current time,

View file

@ -1,710 +1,157 @@
/* /* This file is part of the KDE libraries
* This file is part of the KDE Libraries Copyright (C) 2022 Ivailo Monev <xakepa10@gmail.com>
* Copyright (C) 2000 Timo Hummel <timo.hummel@sap.com>
* Tom Braun <braunt@fh-konstanz.de> This library is free software; you can redistribute it and/or
* Copyright 2009 KDE e.V. modify it under the terms of the GNU Library General Public
* By Adriaan de Groot <groot@kde.org> License version 2, as published by the Free Software Foundation.
* Copyright (C) 2010 George Kiagiadakis <kiagiadakis.george@gmail.com>
* This library is distributed in the hope that it will be useful,
* This library is free software; you can redistribute it and/or but WITHOUT ANY WARRANTY; without even the implied warranty of
* modify it under the terms of the GNU Library General Public MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* License as published by the Free Software Foundation; either Library General Public License for more details.
* version 2 of the License, or (at your option) any later version.
* You should have received a copy of the GNU Library General Public License
* This library is distributed in the hope that it will be useful, along with this library; see the file COPYING.LIB. If not, write to
* but WITHOUT ANY WARRANTY; without even the implied warranty of the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Boston, MA 02110-1301, USA.
* Library General Public License for more details. */
*
* You should have received a copy of the GNU Library General Public License
* along with this library; see the file COPYING.LIB. If not, write to
* the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
* Boston, MA 02110-1301, USA.
*/
#include "kcrash.h" #include "kcrash.h"
#include <kcmdlineargs.h> #include "kcmdlineargs.h"
#include <kstandarddirs.h> #include "kde_file.h"
#include <config-kstandarddirs.h> #include "kaboutdata.h"
#include "kcomponentdata.h"
#include "kstandarddirs.h"
#include "kdebug.h"
#include <config.h> #include <QCoreApplication>
#include <QProcess>
#include <QX11Info>
#include <string.h>
#include <signal.h> #include <signal.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/time.h>
#include <sys/resource.h>
#include <sys/wait.h>
#include <sys/un.h>
#include <sys/socket.h>
#ifdef Q_OS_LINUX
#include <sys/prctl.h>
#endif
#include <errno.h>
#include <qplatformdefs.h>
#include <qwindowdefs.h>
#include <kglobal.h>
#include <kcomponentdata.h>
#include <kaboutdata.h>
#include <kdebug.h>
#include <kapplication.h>
#include <../kinit/klauncher_cmds.h>
#include <QtCore/QFileInfo>
#include <QtCore/QDir>
#if defined Q_WS_X11
#include <qx11info_x11.h>
#include <X11/Xlib.h> #include <X11/Xlib.h>
#endif #include "fixx11h.h"
#ifdef Q_OS_SOLARIS static KCrash::HandlerType s_crashHandler = nullptr;
// Solaris has built-in, thread-safe, async-signal-safe, mechanisms
// to walk the stack in the case of a crash, as well as (optionally)
// to demangle C++ symbol names. In the case of a crash, dump a stack
// trace to stderr before starting drKonqui (because what drKonqui is
// going to do is -- through a complicated process -- print the
// exact same information, but less reliably).
#include <ucontext.h>
#endif
static KCrash::HandlerType s_emergencySaveFunction = 0;
static KCrash::HandlerType s_crashHandler = 0;
static char *s_appName = 0;
static char *s_autoRestartCommand = 0;
static char *s_appPath = 0;
static int s_autoRestartArgc = 0;
static char **s_autoRestartCommandLine = 0;
static char *s_drkonqiPath = 0;
static KCrash::CrashFlags s_flags = 0; static KCrash::CrashFlags s_flags = 0;
static bool s_launchDrKonqi = false;
namespace KCrash
{
void startProcess(int argc, const char *argv[], bool waitAndExit);
}
void
KCrash::setEmergencySaveFunction (HandlerType saveFunction)
{
s_emergencySaveFunction = saveFunction;
/*
* We need at least the default crash handler for
* emergencySaveFunction to be called
*/
if (s_emergencySaveFunction && !s_crashHandler) {
setCrashHandler(defaultCrashHandler);
}
}
KCrash::HandlerType
KCrash::emergencySaveFunction()
{
return s_emergencySaveFunction;
}
// Set the default crash handler in 10 seconds
// This is used after an autorestart, the second instance of the application
// is started with --nocrashhandler (no drkonqi, more precisely), and we
// set the defaultCrashHandler (to handle autorestart) after 10s.
// The delay is to see if we stay up for more than 10s time, to avoid infinite
// respawning if the app crashes on startup.
class KCrashDelaySetHandler : public QObject
{
public:
KCrashDelaySetHandler() {
startTimer(10000); // 10 s
}
protected:
void timerEvent(QTimerEvent *event) {
if (!s_crashHandler) // not set meanwhile
KCrash::setCrashHandler(KCrash::defaultCrashHandler);
killTimer(event->timerId());
this->deleteLater();
}
};
void
KCrash::setFlags(KCrash::CrashFlags flags)
{
s_flags = flags;
if (s_flags & AutoRestart) {
// We need at least the default crash handler for autorestart to work.
if (!s_crashHandler) {
KCmdLineArgs *args = KCmdLineArgs::parsedArgs("kde");
if (!args->isSet("crashhandler")) // --nocrashhandler was passed, probably due to a crash, delay restart handler
new KCrashDelaySetHandler;
else // probably because KDE_DEBUG=1. set restart handler immediately.
setCrashHandler(defaultCrashHandler);
}
}
}
//### KDE5:Consider merging the setApplicationPath and setApplicationName methods into one.
void
KCrash::setApplicationPath(const QString& path)
{
s_appPath = qstrdup(QFile::encodeName(path).constData());
//if the appName has also been specified, update s_autoRestartCommand to be in the form "absolutePath/appName"
if (s_appName) {
delete[] s_autoRestartCommand;
QFileInfo appExecutable(QDir(path), QFile::decodeName(s_appName));
QByteArray cmd = QFile::encodeName(appExecutable.absoluteFilePath());
s_autoRestartCommand = qstrdup(cmd.constData());
}
QStringList args = KCmdLineArgs::allArguments();
args[0] = s_autoRestartCommand; // replace argv[0] with full path above
if (!args.contains("--nocrashhandler"))
args.insert(1, "--nocrashhandler");
delete[] s_autoRestartCommandLine;
s_autoRestartArgc = args.count();
s_autoRestartCommandLine = new char* [args.count() + 1];
for (int i = 0; i < args.count(); ++i) {
s_autoRestartCommandLine[i] = qstrdup(QFile::encodeName(args.at(i)).constData());
}
s_autoRestartCommandLine[args.count()] = 0;
}
void
KCrash::setApplicationName(const QString& name)
{
s_appName = qstrdup(QFile::encodeName(name).constData());
//update the autoRestartCommand
delete[] s_autoRestartCommand;
if (s_appPath) {
//if we have appPath, make autoRestartCommand be in the form "absolutePath/appName"...
QFileInfo appExecutable(QDir(QFile::decodeName(s_appPath)), name);
QByteArray cmd = QFile::encodeName(appExecutable.absoluteFilePath());
s_autoRestartCommand = qstrdup(cmd.constData());
} else {
//...else just use the appName for the autoRestartCommand
s_autoRestartCommand = qstrdup(s_appName);
}
}
void KCrash::setDrKonqiEnabled(bool enabled)
{
s_launchDrKonqi = enabled;
if (s_launchDrKonqi && !s_drkonqiPath) {
s_drkonqiPath = qstrdup(QFile::encodeName(KStandardDirs::findExe("drkonqi")).constData());
if (!s_drkonqiPath) {
kError() << "Could not find drkonqi";
s_launchDrKonqi = false;
}
}
//we need at least the default crash handler to launch drkonqi
if (s_launchDrKonqi && !s_crashHandler) {
setCrashHandler(defaultCrashHandler);
}
}
bool KCrash::isDrKonqiEnabled()
{
return s_launchDrKonqi;
}
void
KCrash::setCrashHandler (HandlerType handler)
{
if (!handler)
handler = SIG_DFL;
sigset_t mask;
sigemptyset(&mask);
static const int s_signals[] = {
#ifdef SIGSEGV #ifdef SIGSEGV
signal (SIGSEGV, handler); SIGSEGV,
sigaddset(&mask, SIGSEGV);
#endif #endif
#ifdef SIGBUS #ifdef SIGBUS
signal (SIGBUS, handler); SIGBUS,
sigaddset(&mask, SIGBUS);
#endif #endif
#ifdef SIGFPE #ifdef SIGFPE
signal (SIGFPE, handler); SIGFPE,
sigaddset(&mask, SIGFPE);
#endif #endif
#ifdef SIGILL #ifdef SIGILL
signal (SIGILL, handler); SIGILL,
sigaddset(&mask, SIGILL);
#endif #endif
#ifdef SIGABRT #ifdef SIGABRT
signal (SIGABRT, handler); SIGABRT,
sigaddset(&mask, SIGABRT);
#endif #endif
0
};
sigprocmask(SIG_UNBLOCK, &mask, 0); void KCrash::setFlags(KCrash::CrashFlags flags)
{
s_crashHandler = handler; s_flags = flags;
if (s_flags & KCrash::AutoRestart || s_flags & KCrash::DrKonqi) {
// Default crash handler is required for the flags to work but one may be set already
if (!s_crashHandler) {
KCmdLineArgs *args = KCmdLineArgs::parsedArgs("kde");
if (args->isSet("crashhandler")) {
setCrashHandler(defaultCrashHandler);
}
}
}
} }
KCrash::HandlerType KCrash::CrashFlags KCrash::flags()
KCrash::crashHandler() {
return s_flags;
}
void KCrash::setCrashHandler(HandlerType handler)
{
if (!handler) {
handler = SIG_DFL;
}
s_crashHandler = handler;
int counter = 0;
while (s_signals[counter]) {
KDE_signal(s_signals[counter], s_crashHandler);
counter++;
}
}
KCrash::HandlerType KCrash::crashHandler()
{ {
return s_crashHandler; return s_crashHandler;
} }
static void void KCrash::defaultCrashHandler(int sig)
closeAllFDs()
{ {
// Close all remaining file descriptors except for stdin/stdout/stderr KDE_signal(sig, SIG_DFL);
struct rlimit rlp;
getrlimit(RLIMIT_NOFILE, &rlp);
for (int i = 3; i < (int)rlp.rlim_cur; i++)
close(i);
}
void #if 0
KCrash::defaultCrashHandler (int sig) kFatal() << QCoreApplication::applicationName() << "crashed" << "(" << QCoreApplication::applicationPid() << ")";
{ return;
// WABA: Do NOT use kDebug() in this function because it is much too risky!
// Handle possible recursions
static int crashRecursionCounter = 0;
crashRecursionCounter++; // Nothing before this, please !
signal(SIGALRM, SIG_DFL);
alarm(3); // Kill me... (in case we deadlock in malloc)
#ifdef Q_OS_SOLARIS
(void) printstack(2 /* stderr, assuming it's still open. */);
#endif #endif
if (crashRecursionCounter < 2) { if (s_flags & KCrash::AutoRestart) {
if (s_emergencySaveFunction) { QStringList args;
s_emergencySaveFunction (sig);
}
if ((s_flags & AutoRestart) && s_autoRestartCommand) {
sleep(1);
startProcess(s_autoRestartArgc, const_cast<const char**>(s_autoRestartCommandLine), false);
}
crashRecursionCounter++;
}
// Note: KCrash closes FDs unconditionally later on if it forks to Dr Konqi // start up on the correct display
// and this program's FDs do not matter if kdeinit starts Dr Konqi. args.append(QString::fromLatin1("-display"));
if (!(s_flags & KeepFDs)) if (QX11Info::display()) {
closeAllFDs(); args.append(XDisplayString(QX11Info::display()));
# if defined(Q_WS_X11) } else {
else if (QX11Info::display()) args.append(QString::fromLocal8Bit(::getenv("DISPLAY")));
close(ConnectionNumber(QX11Info::display()));
# endif
if (crashRecursionCounter < 3)
{
#ifndef NDEBUG
fprintf(stderr, "KCrash: crashing... crashRecursionCounter = %d\n",
crashRecursionCounter);
fprintf(stderr, "KCrash: Application Name = %s path = %s pid = %lld\n",
s_appName ? s_appName : "<unknown>" ,
s_appPath ? s_appPath : "<unknown>", QCoreApplication::applicationPid());
fprintf(stderr, "KCrash: Arguments: ");
for (int i = 0; s_autoRestartCommandLine[i]; ++i) {
fprintf(stderr, "%s ", s_autoRestartCommandLine[i]);
} }
fprintf(stderr, "\n");
#else
fprintf(stderr, "KCrash: Application '%s' crashing...\n",
s_appName ? s_appName : "<unknown>");
#endif
if (!s_launchDrKonqi) { QProcess::startDetached(QCoreApplication::applicationFilePath(), args);
setCrashHandler(0); } else if (s_flags & KCrash::DrKonqi) {
raise(sig); // dump core, or whatever is the default action for this signal. const QString drkonqiexe = KStandardDirs::findExe(QString::fromLatin1("drkonqi"));
if (drkonqiexe.isEmpty()) {
return; return;
} }
const char * argv[27]; // don't forget to update this QStringList args;
int i = 0;
// argument 0 has to be drkonqi args.append(QString::fromLatin1("--signal"));
argv[i++] = s_drkonqiPath; args.append(QString::number(sig));
args.append(QString::fromLatin1("--appname"));
args.append(QCoreApplication::applicationName());
args.append(QString::fromLatin1("--apppath"));
args.append(QCoreApplication::applicationFilePath());
args.append(QString::fromLatin1("--pid"));
args.append(QString::number(QCoreApplication::applicationPid()));
#if defined Q_WS_X11 const KComponentData kcomponentdata = KGlobal::mainComponent();
// start up on the correct display const KAboutData *kaboutdata = kcomponentdata.isValid() ? kcomponentdata.aboutData() : nullptr;
argv[i++] = "-display"; if (kaboutdata) {
if ( QX11Info::display() ) if (kaboutdata->internalVersion()) {
argv[i++] = XDisplayString(QX11Info::display()); args.append(QString::fromLatin1("--appversion"));
else args.append(kaboutdata->internalVersion());
argv[i++] = getenv("DISPLAY");
#elif defined(Q_WS_QWS)
// start up on the correct display
argv[i++] = "-display";
argv[i++] = getenv("QWS_DISPLAY");
#endif
argv[i++] = "--appname";
argv[i++] = s_appName ? s_appName : "<unknown>";
if (KApplication::loadedByKdeinit)
argv[i++] = "--kdeinit";
// only add apppath if it's not NULL
if (s_appPath && *s_appPath) {
argv[i++] = "--apppath";
argv[i++] = s_appPath;
}
// signal number -- will never be NULL
char sigtxt[ 10 ];
sprintf( sigtxt, "%d", sig );
argv[i++] = "--signal";
argv[i++] = sigtxt;
char pidtxt[ 20 ];
sprintf( pidtxt, "%lld", QCoreApplication::applicationPid());
argv[i++] = "--pid";
argv[i++] = pidtxt;
const KComponentData componentData = KGlobal::mainComponent();
const KAboutData *about = componentData.isValid() ? componentData.aboutData() : 0;
if (about) {
if (about->internalVersion()) {
argv[i++] = "--appversion";
argv[i++] = about->internalVersion();
} }
if (about->internalProgramName()) { if (kaboutdata->internalProgramName()) {
argv[i++] = "--programname"; args.append(QString::fromLatin1("--programname"));
argv[i++] = about->internalProgramName(); args.append(kaboutdata->internalProgramName());
} }
if (about->internalBugAddress()) { if (kaboutdata->internalBugAddress()) {
argv[i++] = "--bugaddress"; args.append(QString::fromLatin1("--bugaddress"));
argv[i++] = about->internalBugAddress(); args.append(kaboutdata->internalBugAddress());
} }
} }
char sidtxt[256]; QProcess::execute(drkonqiexe, args);
if ( kapp && !kapp->startupId().isNull()) {
argv[i++] = "--startupid";
strncpy(sidtxt, kapp->startupId().constData(), sizeof(sidtxt));
argv[i++] = sidtxt;
}
if ( s_flags & SaferDialog )
argv[i++] = "--safer";
if ((s_flags & AutoRestart) && s_autoRestartCommand)
argv[i++] = "--restarted"; //tell drkonqi if the app has been restarted
// NULL terminated list
argv[i] = NULL;
startProcess(i, argv, true);
} }
if (crashRecursionCounter < 4) ::exit(sig);
{
fprintf(stderr, "Unable to start Dr. Konqi\n");
}
_exit(255);
} }
static bool startProcessInternal(int argc, const char *argv[], bool waitAndExit, bool directly);
static pid_t startFromKdeinit(int argc, const char *argv[]);
static pid_t startDirectly(const char *argv[]);
static int write_socket(int sock, char *buffer, int len);
static int read_socket(int sock, char *buffer, int len);
static int openSocket();
void KCrash::startProcess(int argc, const char *argv[], bool waitAndExit)
{
bool startDirectly = true;
// First try to start the app via kdeinit, if the AlwaysDirectly flag hasn't been specified.
// This is done because it is dangerous to use fork() in the crash handler
// (there can be functions registered to be performed before fork(), for example handling
// of malloc locking, which doesn't work when malloc crashes because of heap corruption).
// Fails on Apple OSX+KDE4, because kdeinit4 is using the wrong socket name.
if (!(s_flags & AlwaysDirectly)) {
startDirectly = !startProcessInternal(argc, argv, waitAndExit, false);
}
// If we can't reach kdeinit, we can still at least try to fork()
if (startDirectly) {
startProcessInternal(argc, argv, waitAndExit, true);
}
}
static bool startProcessInternal(int argc, const char *argv[], bool waitAndExit, bool directly)
{
fprintf(stderr, "KCrash: Attempting to start %s %s\n", argv[0], directly ? "directly" : "from kdeinit");
pid_t pid = directly ? startDirectly(argv) : startFromKdeinit(argc, argv);
if (pid > 0 && waitAndExit) {
// Seems we made it....
alarm(0); //stop the pending alarm that was set at the top of the defaultCrashHandler
// Wait forever until the started process exits. This code path is executed
// when launching drkonqi. Note that drkonqi will stop this process in the meantime.
if (directly) {
//if the process was started directly, use waitpid(), as it's a child...
while(waitpid(-1, NULL, 0) != pid) {}
} else {
// PR_SET_PTRACER available since 3.4
#if defined(Q_OS_LINUX)
// Declare the process that will be debugging the crashed KDE app (#245529)
prctl(PR_SET_PTRACER, pid, 0, 0, 0);
#endif
//...else poll its status using kill()
while(kill(pid, 0) >= 0) {
sleep(1);
}
}
_exit(253);
}
return (pid > 0); //return true on success
}
static pid_t startFromKdeinit(int argc, const char *argv[])
{
int socket = openSocket();
if( socket < -1 )
return 0;
klauncher_header header;
header.cmd = LAUNCHER_EXEC;
const int BUFSIZE = 8192; // make sure this is big enough
char buffer[ BUFSIZE + 10 ];
int pos = 0;
long argcl = argc;
memcpy( buffer + pos, &argcl, sizeof( argcl ));
pos += sizeof( argcl );
for( int i = 0;
i < argc;
++i )
{
int len = strlen( argv[ i ] ) + 1; // include terminating \0
if( pos + len >= BUFSIZE )
{
fprintf( stderr, "BUFSIZE in KCrash not big enough!\n" );
return 0;
}
memcpy( buffer + pos, argv[ i ], len );
pos += len;
}
long env = 0;
memcpy( buffer + pos, &env, sizeof( env ));
pos += sizeof( env );
long avoid_loops = 0;
memcpy( buffer + pos, &avoid_loops, sizeof( avoid_loops ));
pos += sizeof( avoid_loops );
header.arg_length = pos;
write_socket(socket, (char *) &header, sizeof(header));
write_socket(socket, buffer, pos);
if( read_socket( socket, (char *) &header, sizeof(header)) < 0
|| header.cmd != LAUNCHER_OK )
{
return 0;
}
long pid;
read_socket(socket, (char *) &pid, sizeof(pid));
return static_cast<pid_t>(pid);
}
static pid_t startDirectly(const char *argv[])
{
pid_t pid = fork();
switch (pid)
{
case -1:
fprintf( stderr, "KCrash failed to fork(), errno = %d\n", errno );
return 0;
case 0:
if (setgid(getgid()) < 0 || setuid(getuid()) < 0)
_exit(253); // This cannot happen. Theoretically.
closeAllFDs(); // We are in the child now. Close FDs unconditionally.
execvp(argv[0], const_cast< char** >(argv));
fprintf( stderr, "KCrash failed to exec(), errno = %d\n", errno );
_exit(253);
default:
return pid;
}
}
// From now on this code is copy&pasted from kinit/wrapper.c :
static char *getDisplay()
{
const char *display;
char *result;
char *screen;
char *colon;
char *i;
/*
don't test for a value from qglobal.h but instead distinguish
Qt/X11 from Qt/Embedded by the fact that Qt/E apps have -DQWS
on the commandline (which in qglobal.h however triggers Q_WS_QWS,
but we don't want to include that here) (Simon)
#ifdef Q_WS_X11
*/
#if defined(NO_DISPLAY)
display = "NODISPLAY";
#elif !defined(QWS)
display = getenv("DISPLAY");
#else
display = getenv("QWS_DISPLAY");
#endif
if (!display || !*display)
{
display = ":0";
}
result = (char*)malloc(strlen(display)+1);
if (result == NULL)
return NULL;
strcpy(result, display);
screen = strrchr(result, '.');
colon = strrchr(result, ':');
if (screen && (screen > colon))
*screen = '\0';
while((i = strchr(result, ':')))
*i = '_';
return result;
}
/*
* Write 'len' bytes from 'buffer' into 'sock'.
* returns 0 on success, -1 on failure.
*/
static int write_socket(int sock, char *buffer, int len)
{
ssize_t result;
int bytes_left = len;
while ( bytes_left > 0)
{
result = write(sock, buffer, bytes_left);
if (result > 0)
{
buffer += result;
bytes_left -= result;
}
else if (result == 0)
return -1;
else if ((result == -1) && (errno != EINTR) && (errno != EAGAIN))
return -1;
}
return 0;
}
/*
* Read 'len' bytes from 'sock' into 'buffer'.
* returns 0 on success, -1 on failure.
*/
static int read_socket(int sock, char *buffer, int len)
{
ssize_t result;
int bytes_left = len;
while ( bytes_left > 0)
{
result = read(sock, buffer, bytes_left);
if (result > 0)
{
buffer += result;
bytes_left -= result;
}
else if (result == 0)
return -1;
else if ((result == -1) && (errno != EINTR) && (errno != EAGAIN))
return -1;
}
return 0;
}
static int openSocket()
{
socklen_t socklen;
int s;
struct sockaddr_un server;
#define MAX_SOCK_FILE 255
char sock_file[MAX_SOCK_FILE + 1];
const QByteArray tmp_dir = QFile::encodeName(KGlobal::dirs()->resourceDirs("tmp").first());
char *display;
sock_file[0] = sock_file[MAX_SOCK_FILE] = 0;
if (tmp_dir.isEmpty())
{
fprintf(stderr, "Warning: no temp dir!\n");
return -1;
}
strncat(sock_file, tmp_dir.constData(), MAX_SOCK_FILE - strlen(sock_file));
/** Strip trailing '/' **/
if ( sock_file[strlen(sock_file)-1] == '/')
sock_file[strlen(sock_file)-1] = 0;
sock_file[sizeof(sock_file)-1] = '\0';
/* append $DISPLAY */
display = getDisplay();
#if !defined (NO_DISPLAY)
if (display == NULL)
{
fprintf(stderr, "Error: Could not determine display.\n");
return -1;
}
#endif
if (strlen(sock_file)+strlen(display)+strlen("/kdeinit4_")+2 > MAX_SOCK_FILE)
{
fprintf(stderr, "Warning: Socket name will be too long.\n");
free (display);
return -1;
}
strcat(sock_file, "/kdeinit4_");
#if !defined (NO_DISPLAY)
strcat(sock_file, display);
free(display);
#endif
if (strlen(sock_file) >= sizeof(server.sun_path))
{
fprintf(stderr, "Warning: Path of socketfile exceeds UNIX_PATH_MAX.\n");
return -1;
}
/*
* create the socket stream
*/
s = socket(PF_UNIX, SOCK_STREAM, 0);
if (s < 0)
{
perror("Warning: socket() failed: ");
return -1;
}
server.sun_family = AF_UNIX;
strcpy(server.sun_path, sock_file);
// Use stderr, to make the message visible on the Apple OS X Console log.
fprintf(stderr, "KCrash: Connect sock_file=%s\n", sock_file);
socklen = sizeof(server);
if(connect(s, (struct sockaddr *)&server, socklen) == -1)
{
perror("Warning: connect() failed: ");
close(s);
return -1;
}
return s;
}

View file

@ -1,23 +1,20 @@
/* /* This file is part of the KDE libraries
* This file is part of the KDE Libraries Copyright (C) 2022 Ivailo Monev <xakepa10@gmail.com>
* Copyright (C) 2000 Timo Hummel <timo.hummel@sap.com>
* Tom Braun <braunt@fh-konstanz.de> This library is free software; you can redistribute it and/or
* This library is free software; you can redistribute it and/or modify it under the terms of the GNU Library General Public
* modify it under the terms of the GNU Library General Public License version 2, as published by the Free Software Foundation.
* License as published by the Free Software Foundation; either
* version 2 of the License, or (at your option) any later version. This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* This library is distributed in the hope that it will be useful, MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* but WITHOUT ANY WARRANTY; without even the implied warranty of Library General Public License for more details.
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Library General Public License for more details. You should have received a copy of the GNU Library General Public License
* along with this library; see the file COPYING.LIB. If not, write to
* You should have received a copy of the GNU Library General Public License the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
* along with this library; see the file COPYING.LIB. If not, write to Boston, MA 02110-1301, USA.
* the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, */
* Boston, MA 02110-1301, USA.
*
*/
#ifndef KCRASH_H #ifndef KCRASH_H
#define KCRASH_H #define KCRASH_H
@ -45,110 +42,66 @@
*/ */
namespace KCrash namespace KCrash
{ {
/** /**
* The default crash handler. * The default crash handler.
* Do not call this function directly. Instead, use * Do not call this function directly. Instead, use
* setCrashHandler() to set it as your application's crash handler. * setCrashHandler() to set it as your application's crash handler.
* @param signal the signal number * @param signal the signal number
* @note If you implement your own crash handler, you will have to * @note If you implement your own crash handler, you will have to
* call this function from your implementation if you want to use the * call this function from your implementation if you want to use the
* features of this namespace. * features of this namespace.
*/ */
KDEUI_EXPORT void defaultCrashHandler (int signal); KDEUI_EXPORT void defaultCrashHandler (int signal);
/** /**
* Typedef for a pointer to a crash handler function. * Typedef for a pointer to a crash handler function.
* The function's argument is the number of the signal. * The function's argument is the number of the signal.
*/ */
typedef void (*HandlerType)(int); typedef void (*HandlerType)(int);
/** /**
* Install a function to be called when a crash occurs. * Install a function to be called when a crash occurs.
* A crash occurs when one of the following signals is * A crash occurs when one of the following signals is
* caught: SIGSEGV, SIGBUS, SIGFPE, SIGILL, SIGABRT. * caught: SIGSEGV, SIGBUS, SIGFPE, SIGILL, SIGABRT.
* @param handler this can be one of: * @param handler this can be one of:
* @li null, in which case signal catching is disabled * @li null, in which case signal catching is disabled
* (by setting the signal handler for the crash signals to SIG_DFL) * (by setting the signal handler for the crash signals to SIG_DFL)
* @li a user defined function in the form: * @li a user defined function in the form:
* static (if in a class) void myCrashHandler(int); * static (if in a class) void myCrashHandler(int);
* @li if handler is omitted, the default crash handler is installed * @li if handler is omitted, the default crash handler is installed
* @note If you use setDrKonqiEnabled(true), setEmergencySaveFunction(myfunc) * @note If you use setFlags(AutoRestart), you do not need to call this function
* or setFlags(AutoRestart), you do not need to call this function * explicitly. The default crash handler is automatically installed by
* explicitly. The default crash handler is automatically installed by * those functions if needed. However, if you set a custom crash handler,
* those functions if needed. However, if you set a custom crash handler, * those functions will not change it.
* those functions will not change it. */
*/ KDEUI_EXPORT void setCrashHandler(HandlerType handler = defaultCrashHandler);
KDEUI_EXPORT void setCrashHandler (HandlerType handler = defaultCrashHandler);
/** /**
* Returns the installed crash handler. * Returns the installed crash handler.
* @return the crash handler * @return the crash handler
*/ */
KDEUI_EXPORT HandlerType crashHandler(); KDEUI_EXPORT HandlerType crashHandler();
/** /**
* Installs a function which should try to save the application's data. * Options to determine how the default crash handler should behave.
* @note It is the crash handler's responsibility to call this function. */
* Therefore, if no crash handler is set, the default crash handler enum CrashFlag {
* is installed to ensure the save function will be called. AutoRestart = 1, ///< autorestart this application. Only sensible for KUniqueApplications. @since 4.1.
* @param saveFunction the handler to install DrKonqi = 2 ///< launchers DrKonqi. @since 4.23.
*/ };
KDEUI_EXPORT void setEmergencySaveFunction (HandlerType saveFunction = 0); Q_DECLARE_FLAGS(CrashFlags, CrashFlag)
/** /**
* Returns the currently set emergency save function. * Set options to determine how the default crash handler should behave.
* @return the emergency save function * @param flags ORed together CrashFlags
*/ */
KDEUI_EXPORT HandlerType emergencySaveFunction(); KDEUI_EXPORT void setFlags(CrashFlags flags);
/** /**
* Options to determine how the default crash handler should behave. * Get currently set options that determine how the default crash handler should behave.
*/ * @param flags ORed together CrashFlags
enum CrashFlag { */
KeepFDs = 1, ///< don't close all file descriptors immediately KDEUI_EXPORT CrashFlags flags();
SaferDialog = 2, ///< start DrKonqi without arbitrary disk access
AlwaysDirectly = 4, ///< never try to to start DrKonqi via kdeinit. Use fork() and exec() instead.
AutoRestart = 8 ///< autorestart this application. Only sensible for KUniqueApplications. @since 4.1.
};
Q_DECLARE_FLAGS(CrashFlags, CrashFlag)
/**
* Set options to determine how the default crash handler should behave.
* @param flags ORed together CrashFlags
*/
KDEUI_EXPORT void setFlags( CrashFlags flags );
/**
* Sets the application @p path which should be passed to
* DrKonqi, our nice crash display application.
* @param path the application path
*/
KDEUI_EXPORT void setApplicationPath (const QString &path);
/**
* Sets the application @p name which should be passed to
* DrKonqi, our nice crash display application.
* @param name the name of the application, as shown in DrKonqi
*/
KDEUI_EXPORT void setApplicationName (const QString &name);
/**
* Enables or disables launching DrKonqi from the crash handler.
* By default, launching DrKonqi is disabled. However, KApplication
* will enable it in its constructor, so you don't need to call this
* function if you are using KApplication.
* @note It is the crash handler's responsibility to launch DrKonqi.
* Therefore, if no crash handler is set, this method also installs
* the default crash handler to ensure that DrKonqi will be launched.
* @since 4.5
*/
KDEUI_EXPORT void setDrKonqiEnabled(bool enabled);
/**
* Returns true if DrKonqi is set to be launched from the crash handler or false otherwise.
* @since 4.5
*/
KDEUI_EXPORT bool isDrKonqiEnabled();
} }
Q_DECLARE_OPERATORS_FOR_FLAGS(KCrash::CrashFlags) Q_DECLARE_OPERATORS_FOR_FLAGS(KCrash::CrashFlags)

View file

@ -1,45 +1,10 @@
project(kdeinit) project(kinit)
if(ENABLE_TESTING) if(ENABLE_TESTING)
add_subdirectory(tests) add_subdirectory(tests)
endif() endif()
include_directories(${KDE4_KPARTS_INCLUDES}) add_definitions(-DKDE_DEFAULT_DEBUG_AREA=1210)
########### Configuring (mainly for proctitle) ###########
include(CheckFunctionExists)
include(CheckVariableExists)
check_variable_exists(__progname HAVE___PROGNAME)
check_variable_exists(__progname_full HAVE___PROGNAME_FULL)
check_function_exists(setproctitle HAVE_SETPROCTITLE)
set(KINIT_SOCKET_LIBRARY)
if(HAVE_SOCKET_LIBRARY)
set(KINIT_SOCKET_LIBRARY socket)
endif()
if (NOT Q_WS_X11 AND NOT Q_WS_QWS)
add_definitions(-DNO_DISPLAY)
endif()
########### kdeinit4 ###############
set(kdeinit_SRCS
kinit.cpp
proctitle.cpp
klauncher_cmds.cpp
)
add_executable(kdeinit4 ${kdeinit_SRCS})
target_link_libraries(kdeinit4 ${KDE4_KDEUI_LIBS} ${KINIT_SOCKET_LIBRARY})
if (Q_WS_X11)
target_link_libraries(kdeinit4 ${X11_X11_LIB})
endif()
install(TARGETS kdeinit4 ${INSTALL_TARGETS_DEFAULT_ARGS})
########### kioslave ############### ########### kioslave ###############
@ -49,14 +14,11 @@ target_link_libraries(kioslave ${QT_QTCORE_LIBRARY})
install(TARGETS kioslave DESTINATION ${KDE4_LIBEXEC_INSTALL_DIR}) install(TARGETS kioslave DESTINATION ${KDE4_LIBEXEC_INSTALL_DIR})
########### klauncher ############### ########### klauncher ###############
set(klauncher_SRCS set(klauncher_SRCS
klauncher.cpp klauncher.cpp
klauncher_main.cpp
klauncher_adaptor.cpp klauncher_adaptor.cpp
autostart.cpp
klauncher_cmds.cpp
# just so that it gets generated # just so that it gets generated
${CMAKE_CURRENT_BINARY_DIR}/org.kde.KLauncher.xml ${CMAKE_CURRENT_BINARY_DIR}/org.kde.KLauncher.xml
) )
@ -64,11 +26,16 @@ set(klauncher_SRCS
# The adaptor is manually edited, generate the xml from it. # The adaptor is manually edited, generate the xml from it.
qt4_generate_dbus_interface(klauncher_adaptor.h org.kde.KLauncher.xml) qt4_generate_dbus_interface(klauncher_adaptor.h org.kde.KLauncher.xml)
add_executable(klauncher ${klauncher_SRCS}) add_executable(klauncher4 ${klauncher_SRCS})
target_link_libraries(klauncher ${KDE4_KIO_LIBS} ${X11_LIBRARIES}) target_link_libraries(klauncher4
${KDE4_KDEUI_LIBS}
${KDE4_KIO_LIBS}
)
install(TARGETS klauncher DESTINATION ${KDE4_LIBEXEC_INSTALL_DIR}) kde4_add_dbus_service(org.kde.klauncher.service.in)
install(TARGETS klauncher4 DESTINATION ${KDE4_BIN_INSTALL_DIR})
########### install files ############### ########### install files ###############
@ -77,10 +44,3 @@ install(
${CMAKE_CURRENT_BINARY_DIR}/org.kde.KLauncher.xml ${CMAKE_CURRENT_BINARY_DIR}/org.kde.KLauncher.xml
DESTINATION ${KDE4_DBUS_INTERFACES_INSTALL_DIR} DESTINATION ${KDE4_DBUS_INTERFACES_INSTALL_DIR}
) )
########### config-kdeinit.h ############
configure_file(
config-kdeinit.h.cmake
${CMAKE_CURRENT_BINARY_DIR}/config-kdeinit.h
)

View file

@ -1,122 +0,0 @@
/*
* This file is part of the KDE libraries
* Copyright (c) 2001 Waldo Bastian <bastian@kde.org>
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Library General Public
* License version 2 as published by the Free Software Foundation.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Library General Public License for more details.
*
* You should have received a copy of the GNU Library General Public License
* along with this library; see the file COPYING.LIB. If not, write to
* the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
* Boston, MA 02110-1301, USA.
**/
#define QT_NO_CAST_FROM_ASCII
#include "autostart.h"
#include <kautostart.h>
#include <kglobal.h>
#include <kstandarddirs.h>
class AutoStartItem
{
public:
QString name;
QString service;
int phase;
};
AutoStart::AutoStart()
: m_phase(-1), m_phasedone(false)
{
m_startList = new AutoStartList;
KGlobal::dirs()->addResourceType("xdgconf-autostart", NULL, QLatin1String("autostart/")); // xdg ones
KGlobal::dirs()->addResourceType("autostart", "xdgconf-autostart", QLatin1String("/")); // merge them
KGlobal::dirs()->addResourceType("autostart", 0, QLatin1String("share/autostart")); // KDE ones are higher priority
}
AutoStart::~AutoStart()
{
qDeleteAll(*m_startList);
m_startList->clear();
delete m_startList;
}
void
AutoStart::setPhase(int phase)
{
if (phase > m_phase)
{
m_phase = phase;
m_phasedone = false;
}
}
void AutoStart::setPhaseDone()
{
m_phasedone = true;
}
static QString extractName(QString path) // krazy:exclude=passbyvalue
{
int i = path.lastIndexOf(QLatin1Char('/'));
if (i >= 0)
path = path.mid(i+1);
i = path.lastIndexOf(QLatin1Char('.'));
if (i >= 0)
path = path.left(i);
return path;
}
void
AutoStart::loadAutoStartList()
{
const QStringList files = KGlobal::dirs()->findAllResources("autostart",
QString::fromLatin1("*.desktop"),
KStandardDirs::NoDuplicates);
foreach(const QString it, files)
{
KAutostart config(it);
if( !config.autostarts(QString::fromLatin1("KDE"), KAutostart::CheckAll))
continue;
AutoStartItem *item = new AutoStartItem;
item->name = extractName(it);
item->service = it;
item->phase = config.startPhase();
if (item->phase < 0)
item->phase = 0;
m_startList->append(item);
}
}
QString
AutoStart::startService()
{
if (m_startList->isEmpty())
return QString();
// Just start something in this phase
QMutableListIterator<AutoStartItem *> it(*m_startList);
while (it.hasNext())
{
AutoStartItem *item = it.next();
if (item->phase == m_phase)
{
m_started.prepend(item->name);
QString service = item->service;
it.remove();
delete item;
return service;
}
}
return QString();
}

View file

@ -1,48 +0,0 @@
/*
This file is part of the KDE libraries
Copyright (c) 2001 Waldo Bastian <bastian@kde.org>
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Library General Public
License version 2 as published by the Free Software Foundation.
This library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Library General Public License for more details.
You should have received a copy of the GNU Library General Public License
along with this library; see the file COPYING.LIB. If not, write to
the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
Boston, MA 02110-1301, USA.
*/
#ifndef _AUTOSTART_H_
#define _AUTOSTART_H_
#include <QtCore/QStringList>
class AutoStartItem;
typedef QList<AutoStartItem *> AutoStartList;
class AutoStart
{
public:
AutoStart();
~AutoStart();
void loadAutoStartList();
QString startService();
void setPhase(int phase);
void setPhaseDone();
int phase() const { return m_phase; }
bool phaseDone() const { return m_phasedone; }
private:
AutoStartList *m_startList;
QStringList m_started;
int m_phase;
bool m_phasedone;
};
#endif

View file

@ -1,5 +0,0 @@
/* These are for proctitle.cpp: */
#cmakedefine HAVE___PROGNAME 1
#cmakedefine HAVE___PROGNAME_FULL 1
#cmakedefine HAVE_SETPROCTITLE 1

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

View file

@ -1,251 +1,39 @@
/* /* This file is part of the KDE libraries
This file is part of the KDE libraries Copyright (C) 2022 Ivailo Monev <xakepa10@gmail.com>
Copyright (c) 1999 Waldo Bastian <bastian@kde.org>
This library is free software; you can redistribute it and/or This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Library General Public modify it under the terms of the GNU Library General Public
License version 2 as published by the Free Software Foundation. License version 2, as published by the Free Software Foundation.
This library is distributed in the hope that it will be useful, This library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Library General Public License for more details. Library General Public License for more details.
You should have received a copy of the GNU Library General Public License You should have received a copy of the GNU Library General Public License
along with this library; see the file COPYING.LIB. If not, write to along with this library; see the file COPYING.LIB. If not, write to
the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
Boston, MA 02110-1301, USA. Boston, MA 02110-1301, USA.
*/ */
#ifndef _KLAUNCHER_H_ #ifndef KLAUNCHER_H
#define _KLAUNCHER_H_ #define KLAUNCHER_H
#include "autostart.h" #include "klauncher_adaptor.h"
#include <sys/types.h> #include <QObject>
#include <unistd.h>
#include <time.h>
#ifdef Q_WS_X11
#include <X11/Xlib.h>
#include <fixx11h.h>
#endif
#include <QtCore/QSocketNotifier>
#include <QtCore/QTimer>
#include <QtDBus/QDBusMessage>
#include <QtDBus/QDBusConnectionInterface>
#include <kservice.h>
#include <kurl.h>
#include <kio/connection.h>
class IdleSlave : public QObject
{
Q_OBJECT
public:
explicit IdleSlave(QObject *parent);
bool match( const QString &protocol, const QString &host, bool connected) const;
void connect( const QString &app_socket);
pid_t pid() const { return mPid;}
int age(time_t now) const;
void reparseConfiguration();
bool onHold(const KUrl &url) const;
QString protocol() const {return mProtocol;}
Q_SIGNALS:
void statusUpdate(IdleSlave *);
protected Q_SLOTS:
void gotInput();
public:
KIO::Connection mConn;
protected:
QString mProtocol;
QString mHost;
bool mConnected;
pid_t mPid;
time_t mBirthDate;
bool mOnHold;
KUrl mUrl;
};
class SlaveWaitRequest
{
public:
pid_t pid;
QDBusMessage transaction;
};
class KLaunchRequest
{
public:
QString name;
QStringList arg_list;
QString dbus_name;
QString tolerant_dbus_name;
enum status_t { Init = 0, Launching, Running, Error, Done };
pid_t pid;
status_t status;
QDBusMessage transaction;
KService::DBusStartupType dbus_startup_type;
bool autoStart;
QString errorMsg;
#ifdef Q_WS_X11
QByteArray startup_id; // "" is the default, "0" for none
QByteArray startup_dpy; // Display to send startup notification to.
#endif
QStringList envs; // env. variables to be app's environment
QString cwd;
};
struct serviceResult
{
int result; // 0 means success. > 0 means error (-1 means pending)
QString dbusName; // Contains DBUS name on success
QString error; // Contains error description on failure.
pid_t pid;
};
class KLauncher : public QObject class KLauncher : public QObject
{ {
Q_OBJECT Q_OBJECT
public: public:
KLauncher(int kdeinitSocket); KLauncher(QObject *parent = nullptr);
~KLauncher();
~KLauncher(); void setSessionManager(const QByteArray &sessionmanager);
void close(); private:
KLauncherAdaptor* m_adaptor;
public slots:
void destruct(); // exit!
protected:
void processDied(pid_t pid, long exitStatus);
void requestStart(KLaunchRequest *request);
void requestDone(KLaunchRequest *request);
bool start_service(KService::Ptr service, const QStringList &urls,
const QStringList &envs, const QByteArray &startup_id,
bool blind, bool autoStart, QDBusMessage msg );
void createArgs( KLaunchRequest *request, const KService::Ptr service,
const QStringList &url);
void queueRequest(KLaunchRequest *);
void send_service_startup_info( KLaunchRequest *request, KService::Ptr service, const QByteArray &startup_id,
const QStringList &envs );
void cancel_service_startup_info( KLaunchRequest *request, const QByteArray& startup_id,
const QStringList &envs );
Q_SIGNALS:
void autoStart0Done();
void autoStart1Done();
void autoStart2Done();
public: // remote methods, called by KLauncherAdaptor
void autoStart(int phase = 1);
/**
* Starts a program.
*/
void exec_blind(const QString &name, const QStringList &arg_list);
bool kdeinit_exec(const QString &app, const QStringList &args,
const QString& workdir, const QStringList &envs,
const QString &startup_id, bool wait, QDBusMessage msg);
void reparseConfiguration();
void setLaunchEnv(const QString &name, const QString &value);
/**
* Start a service by desktop name.
*
* 'serviceName' refers to a desktop file describing the service.
* The service is looked up anywhere in $KDEDIR/applnk and/or
* $KDEDIR/services.
* E.g. it should have the form "korganizer".
*
* 'url', if not empty, will be passed to the service as
* argument.
*
* 'envs' are environment variables that will be added
* to this program's environment before starting it
*
* 'startup_id' is for application startup notification,
* "" is the default, "0" for none
*/
bool start_service_by_desktop_name(const QString &serviceName, const QStringList &urls, const QStringList &envs, const QString &startup_id, bool blind, const QDBusMessage &msg);
/**
* Start a service by desktop path.
*
* 'serviceName' refers to a desktop file describing the service.
* This may be an absolute path or a path relative to $KDEDIRS/applnk
* and/or $KDEDIRS/services
* E.g. it should have the form "Applications/korganizer.desktop" or
* "/opt/kde/share/applnk/Applications/korganizer.desktop".
* Note that for absolute paths the restrictions of
* KDesktopFile::isAuthorizedDesktopFile() are obeyed for security.
*
* 'url', if not empty, will be passed to the service as
* argument.
*
* 'envs' are environment variables that will be added
* to this program's environment before starting it
*
* 'startup_id' is for application startup notification,
* "" is the default, "0" for none
*/
bool start_service_by_desktop_path(const QString &serviceName, const QStringList &urls, const QStringList &envs, const QString &startup_id, bool blind, const QDBusMessage &msg);
pid_t requestHoldSlave(const KUrl &url, const QString &app_socket);
pid_t requestSlave(const QString &protocol, const QString &host,
const QString &app_socket, QString &error);
/**
* Return true of there is a slave held for @p url.
* @since 4.7
*/
bool checkForHeldSlave(const QString &url);
void waitForSlave(pid_t pid, QDBusMessage msg);
void terminate_kdeinit();
public Q_SLOTS:
void slotAutoStart();
void slotDequeue();
void slotKDEInitData(int);
void slotNameOwnerChanged(const QString &name, const QString &oldOnwer, const QString &newOwner);
void slotSlaveStatus(IdleSlave *);
void acceptSlave();
void slotSlaveGone();
void idleTimeout();
public:
serviceResult requestResult; // accessed by the adaptor
protected:
QList<KLaunchRequest*> requestList; // Requests being handled
QList<KLaunchRequest*> requestQueue; // Requests waiting to being handled
KLaunchRequest *lastRequest;
QList<SlaveWaitRequest*> mSlaveWaitRequest;
int kdeinitSocket;
QSocketNotifier *kdeinitNotifier;
KIO::ConnectionServer mConnectionServer;
QList<IdleSlave*> mSlaveList;
QTimer mTimer;
QTimer mAutoTimer;
bool bProcessingQueue;
AutoStart mAutoStart;
QString mSlaveDebug;
QString mSlaveValgrind;
QString mSlaveValgrindSkin;
#ifdef Q_WS_X11
Display *mCached_dpy;
#endif
void processRequestReturn(int status, const QByteArray &requestData);
}; };
#endif
#endif // KLAUNCHER_H

View file

@ -1,141 +1,351 @@
/* /* This file is part of the KDE libraries
* Copyright 2006, 2007 Thiago Macieira <thiago@kde.org> Copyright (C) 2022 Ivailo Monev <xakepa10@gmail.com>
* Copyright 2006-2008 David Faure <faure@kde.org>
* This library is free software; you can redistribute it and/or
* This library is free software; you can redistribute it and/or modify it under the terms of the GNU Library General Public
* modify it under the terms of the GNU Lesser General Public License version 2, as published by the Free Software Foundation.
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) version 3, or any This library is distributed in the hope that it will be useful,
* later version accepted by the membership of KDE e.V. (or its but WITHOUT ANY WARRANTY; without even the implied warranty of
* successor approved by the membership of KDE e.V.), which shall MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* act as a proxy defined in Section 6 of version 3 of the license. Library General Public License for more details.
*
* This library is distributed in the hope that it will be useful, You should have received a copy of the GNU Library General Public License
* but WITHOUT ANY WARRANTY; without even the implied warranty of along with this library; see the file COPYING.LIB. If not, write to
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
* Lesser General Public License for more details. Boston, MA 02110-1301, USA.
* */
* You should have received a copy of the GNU Lesser General Public
* License along with this library. If not, see <http://www.gnu.org/licenses/>.
*
*/
#include "klauncher_adaptor.h" #include "klauncher_adaptor.h"
#include "klauncher.h" #include "kprotocolmanager.h"
#include "krun.h"
#include "kstandarddirs.h"
#include "kautostart.h"
#include "kdebug.h"
/* #include <QDir>
* Implementation of adaptor class KLauncherAdaptor #include <QApplication>
* #include <QThread>
* This file was initially generated by dbusidl2cpp version 0.4, #include <QElapsedTimer>
* but then modified by hand. #include <QDBusConnection>
*/ #include <QDBusConnectionInterface>
#include <QDBusReply>
#include <sys/types.h>
#include <sys/wait.h>
static const int s_eventstime = 250;
static const int s_sleeptime = 50;
static const qint64 s_servicetimeout = 10000; // 10sec
KLauncherAdaptor::KLauncherAdaptor(QObject *parent) KLauncherAdaptor::KLauncherAdaptor(QObject *parent)
: QDBusAbstractAdaptor(parent) : QDBusAbstractAdaptor(parent)
{ {
// constructor m_environment = QProcessEnvironment::systemEnvironment();
setAutoRelaySignals(true);
} }
KLauncherAdaptor::~KLauncherAdaptor() KLauncherAdaptor::~KLauncherAdaptor()
{ {
// destructor kDebug() << "terminating processes" << m_processes.size();
while (!m_processes.isEmpty()) {
QProcess* process = m_processes.takeLast();
disconnect(process, 0, this, 0);
process->terminate();
process->waitForFinished();
}
} }
void KLauncherAdaptor::autoStart(int phase) void KLauncherAdaptor::autoStart(int phase)
{ {
// handle method call org.kde.KLauncher.autoStart if (m_autostart.isEmpty()) {
static_cast<KLauncher *>(parent())->autoStart(phase); m_autostart = KGlobal::dirs()->findAllResources(
"autostart",
QString::fromLatin1("*.desktop"),
KStandardDirs::NoDuplicates
);
}
kDebug() << "autostart, phase" << phase;
foreach(const QString &it, m_autostart) {
KAutostart kautostart(it);
if (!kautostart.autostarts(QString::fromLatin1("KDE"), KAutostart::CheckAll)) {
continue;
}
if (kautostart.startPhase() != phase) {
continue;
}
KService kservice(it);
QStringList programandargs = KRun::processDesktopExec(kservice, KUrl::List());
if (programandargs.isEmpty()) {
kWarning() << "could not process service" << kservice.entryPath();
continue;
}
const QString program = programandargs.takeFirst();
const QStringList programargs = programandargs;
exec_blind(program, programargs);
}
switch (phase) {
case 0: {
emit autoStart0Done();
break;
}
case 1: {
emit autoStart1Done();
break;
}
case 2: {
emit autoStart2Done();
break;
}
}
} }
void KLauncherAdaptor::exec_blind(const QString &name, const QStringList &arg_list) void KLauncherAdaptor::exec_blind(const QString &name, const QStringList &arg_list)
{ {
// handle method call org.kde.KLauncher.exec_blind const QString appexe = findExe(name);
static_cast<KLauncher *>(parent())->exec_blind(name, arg_list); if (appexe.isEmpty()) {
kWarning() << "Could not find" << name;
return;
}
kDebug() << "blind starting" << appexe << arg_list << m_environment.toStringList();
const QString envexe = findExe("env");
if (envexe.isEmpty()) {
kWarning() << "env program not found";
QProcess::startDetached(appexe, arg_list);
return;
}
QStringList envargs = m_environment.toStringList();
envargs += appexe;
envargs += arg_list;
QProcess::startDetached(envexe, envargs);
} }
int KLauncherAdaptor::kdeinit_exec(const QString &app, const QStringList &args, const QStringList &env, const QString& startup_id, const QDBusMessage &msg, QString &, QString &, qint64 &) int KLauncherAdaptor::kdeinit_exec(const QString &app, const QStringList &args, const QStringList &env, const QString& startup_id,
const QDBusMessage &msg, QString &dbusServiceName, QString &error, qint64 &pid)
{ {
// handle method call org.kde.KLauncher.kdeinit_exec return kdeinit_exec_with_workdir(app, args, QDir::currentPath(), env, startup_id, msg, dbusServiceName, error, pid);
static_cast<KLauncher *>(parent())->kdeinit_exec(app, args, QString(), env, startup_id, false, msg);
return 0; // delayed reply
} }
int KLauncherAdaptor::kdeinit_exec_wait(const QString &app, const QStringList &args, const QStringList &env, const QString& startup_id, const QDBusMessage &msg, QString &, QString &, qint64 &) int KLauncherAdaptor::kdeinit_exec_wait(const QString &app, const QStringList &args, const QStringList &env, const QString& startup_id,
const QDBusMessage &msg, QString &dbusServiceName, QString &error, qint64 &pid)
{ {
// handle method call org.kde.KLauncher.kdeinit_exec_wait const int result = kdeinit_exec(app, args, env, startup_id, msg, dbusServiceName, error, pid);
static_cast<KLauncher *>(parent())->kdeinit_exec(app, args, QString(), env, startup_id, true, msg); if (result != KLauncherAdaptor::NoError) {
return 0; // delayed reply return result;
}
kDebug() << "waiting for" << pid;
while (::kill(pid, 0) >= 0) {
QApplication::processEvents(QEventLoop::AllEvents, s_eventstime);
QThread::msleep(s_sleeptime);
}
int pidstate = 0;
::waitpid(pid, &pidstate, WNOHANG);
kDebug() << "done waiting for" << pid << ", exit status" << WEXITSTATUS(pidstate);
return WEXITSTATUS(pidstate);
} }
int KLauncherAdaptor::kdeinit_exec_with_workdir(const QString &app, const QStringList &args, const QString& workdir, const QStringList &env, const QString& startup_id, const QDBusMessage &msg, QString &, QString &, qint64 &) int KLauncherAdaptor::kdeinit_exec_with_workdir(const QString &app, const QStringList &args, const QString& workdir, const QStringList &env, const QString& startup_id,
const QDBusMessage &msg, QString &dbusServiceName, QString &error, qint64 &pid)
{ {
// handle method call org.kde.KLauncher.kdeinit_exec_with_workdir const QString appexe = findExe(app);
static_cast<KLauncher *>(parent())->kdeinit_exec(app, args, workdir, env, startup_id, false, msg); if (appexe.isEmpty()) {
return 0; // delayed reply error = i18n("Could not find: %1", app);
return KLauncherAdaptor::FindError;
}
QProcess* process = new QProcess(this);
connect(process, SIGNAL(stateChanged(QProcess::ProcessState)), this, SLOT(slotProcessStateChanged(QProcess::ProcessState)));
connect(process, SIGNAL(finished(int)), this, SLOT(slotProcessFinished(int)));
m_processes.append(process);
QProcessEnvironment processenv = m_environment;
foreach (const QString &it, env) {
const int equalindex = it.indexOf(QLatin1Char('='));
if (equalindex <= 0) {
kWarning() << "Invalid environment variable" << it;
continue;
}
const QString environmentvar = it.mid(0, equalindex);
const QString environmentvalue = it.mid(equalindex + 1, it.size() - equalindex - 1);
kDebug() << "adding to environment" << environmentvar << environmentvalue;
processenv.insert(environmentvar, environmentvalue);
}
process->setProcessEnvironment(processenv);
process->setWorkingDirectory(workdir);
kDebug() << "starting" << appexe << args << env << processenv.toStringList();
m_kstartupinfoid = KStartupInfoId();
m_kstartupinfoid.initId(startup_id.toLatin1());
m_kstartupinfodata = KStartupInfoData();
m_kstartupinfodata.setBin(appexe);
process->start(appexe, args);
sendSIStart();
while (process->state() == QProcess::Starting) {
QApplication::processEvents(QEventLoop::AllEvents, s_eventstime);
QThread::msleep(s_sleeptime);
}
if (process->error() == QProcess::FailedToStart || process->error() == QProcess::Crashed) {
sendSIFinish();
error = i18n("Could not start: %1", appexe);
return KLauncherAdaptor::ExecError;
}
if (dbusServiceName.isEmpty()) {
// if service name is not empty it will be send when the service is up
sendSIFinish();
}
error.clear();
pid = process->pid();
return KLauncherAdaptor::NoError;
} }
void KLauncherAdaptor::reparseConfiguration() void KLauncherAdaptor::reparseConfiguration()
{ {
// handle method call org.kde.KLauncher.reparseConfiguration kDebug() << "reparsing configuration";
static_cast<KLauncher *>(parent())->reparseConfiguration(); KProtocolManager::reparseConfiguration();
}
qint64 KLauncherAdaptor::requestHoldSlave(const QString &url, const QString &app_socket)
{
// handle method call org.kde.KLauncher.requestHoldSlave
return static_cast<KLauncher *>(parent())->requestHoldSlave(KUrl(url), app_socket);
}
qint64 KLauncherAdaptor::requestSlave(const QString &protocol, const QString &host, const QString &app_socket, QString &error)
{
// handle method call org.kde.KLauncher.requestSlave
return static_cast<KLauncher *>(parent())->requestSlave(protocol, host, app_socket, error);
}
bool KLauncherAdaptor::checkForHeldSlave (const QString &url)
{
return static_cast<KLauncher *>(parent())->checkForHeldSlave(url);
} }
void KLauncherAdaptor::setLaunchEnv(const QString &name, const QString &value) void KLauncherAdaptor::setLaunchEnv(const QString &name, const QString &value)
{ {
// handle method call org.kde.KLauncher.setLaunchEnv kDebug() << "setting environment variable" << name << "to" << value;
static_cast<KLauncher *>(parent())->setLaunchEnv(name, value); m_environment.insert(name, value);
} }
int KLauncherAdaptor::start_service_by_desktop_name(const QString &serviceName, const QStringList &urls, const QStringList &envs, const QString &startup_id, bool blind, const QDBusMessage &msg, QString &dbusServiceName, QString &error, qint64 &pid) int KLauncherAdaptor::start_service_by_desktop_name(const QString &serviceName, const QStringList &urls, const QStringList &envs, const QString &startup_id, bool blind,
const QDBusMessage &msg, QString &dbusServiceName, QString &error, qint64 &pid)
{ {
// handle method call org.kde.KLauncher.start_service_by_desktop_name KService::Ptr kservice = KService::serviceByDesktopName(serviceName);
KLauncher *p = static_cast<KLauncher *>(parent()); if (!kservice) {
p->start_service_by_desktop_name(serviceName, urls, envs, startup_id, blind, msg); error = i18n("Invalid service name: %1", serviceName);
dbusServiceName = p->requestResult.dbusName; return KLauncherAdaptor::ServiceError;
error = p->requestResult.error; }
pid = p->requestResult.pid; return start_service_by_desktop_path(kservice->entryPath(), urls, envs, startup_id, blind, msg, dbusServiceName, error, pid);
return p->requestResult.result;
} }
int KLauncherAdaptor::start_service_by_desktop_path(const QString &serviceName, const QStringList &urls, const QStringList &envs, const QString &startup_id, bool blind, const QDBusMessage &msg, QString &dbusServiceName, QString &error, qint64 &pid) int KLauncherAdaptor::start_service_by_desktop_path(const QString &serviceName, const QStringList &urls, const QStringList &envs, const QString &startup_id, bool blind,
const QDBusMessage &msg, QString &dbusServiceName, QString &error, qint64 &pid)
{ {
// handle method call org.kde.KLauncher.start_service_by_desktop_path KService::Ptr kservice = KService::serviceByStorageId(serviceName);
KLauncher *p = static_cast<KLauncher *>(parent()); if (!kservice) {
p->start_service_by_desktop_path(serviceName, urls, envs, startup_id, blind, msg); error = i18n("Invalid service path: %1", serviceName);
dbusServiceName = p->requestResult.dbusName; return KLauncherAdaptor::ServiceError;
error = p->requestResult.error; }
pid = p->requestResult.pid; if (urls.size() > 1 && !kservice->allowMultipleFiles()) {
return p->requestResult.result; // TODO: start multiple instances for each URL
error = i18n("Service does not support multiple files: %1", serviceName);
return KLauncherAdaptor::ServiceError;
}
QStringList programandargs = KRun::processDesktopExec(*kservice, urls);
if (programandargs.isEmpty()) {
error = i18n("Could not process service: %1", kservice->entryPath());
return KLauncherAdaptor::ArgumentsError;
}
const QString program = programandargs.takeFirst();
const QStringList programargs = programandargs;
const KService::DBusStartupType dbusstartuptype = kservice->dbusStartupType();
dbusServiceName = kservice->property(QString::fromLatin1("X-DBUS-ServiceName"), QVariant::String).toString();
const int result = kdeinit_exec(program, programargs, envs, startup_id, msg, dbusServiceName, error, pid);
if (result != KLauncherAdaptor::NoError) {
// sendSIFinish() is called on exec error
return result;
}
// blind means do not wait, even if its type is wait
if (blind || dbusstartuptype == KService::DBusNone) {
sendSIFinish();
return result;
} else if (dbusstartuptype != KService::DBusNone && dbusServiceName.isEmpty()) {
// not going to guess what service to wait for, bud
kWarning() << "X-DBUS-ServiceName not specified in" << kservice->entryPath();
sendSIFinish();
return result;
} else if (dbusstartuptype == KService::DBusMulti) {
dbusServiceName.append(QLatin1Char('-'));
dbusServiceName.append(QString::number(pid));
}
kDebug() << "waiting for" << pid << dbusServiceName;
QDBusConnection session = QDBusConnection::sessionBus();
QElapsedTimer elapsedtime;
elapsedtime.start();
while (true) {
QDBusReply<bool> sessionreply = session.interface()->isServiceRegistered(dbusServiceName);
if (!sessionreply.isValid()) {
sendSIFinish();
error = i18n("Invalid D-Bus reply for: %1", dbusServiceName);
return KLauncherAdaptor::DBusError;
}
// the service unregistered
if (sessionreply.value() == false && dbusstartuptype == KService::DBusWait) {
break;
}
// the service registered
if (sessionreply.value() == true && dbusstartuptype != KService::DBusWait) {
break;
}
// or the program is just not registering the service at all
if (elapsedtime.elapsed() >= s_servicetimeout && dbusstartuptype != KService::DBusWait) {
kWarning() << "timed out for" << pid << ", service name" << dbusServiceName;
break;
}
QApplication::processEvents(QEventLoop::AllEvents, s_eventstime);
QThread::msleep(s_sleeptime);
}
kDebug() << "done waiting for" << pid << ", service name" << dbusServiceName;
sendSIFinish();
return result;
} }
void KLauncherAdaptor::waitForSlave(qint64 pid, const QDBusMessage &msg) void KLauncherAdaptor::slotProcessStateChanged(QProcess::ProcessState state)
{ {
// handle method call org.kde.KLauncher.waitForSlave QProcess* process = qobject_cast<QProcess*>(sender());
static_cast<KLauncher *>(parent())->waitForSlave(pid, msg); kDebug() << "process state changed" << process << state;
if (state == QProcess::Starting && !m_kstartupinfoid.none()) {
m_kstartupinfodata.addPid(process->pid());
sendSIUpdate();
} else if (state == QProcess::NotRunning && m_kstartupinfodata.is_pid(process->pid())) {
sendSIFinish();
}
} }
void KLauncherAdaptor::terminate_kdeinit() void KLauncherAdaptor::slotProcessFinished(int exitcode)
{ {
KLauncher *p = static_cast<KLauncher *>(parent()); QProcess* process = qobject_cast<QProcess*>(sender());
p->terminate_kdeinit(); kDebug() << "process finished" << process << exitcode;
m_processes.removeAll(process);
}
QString KLauncherAdaptor::findExe(const QString &app) const
{
if (QDir::isAbsolutePath(app)) {
return app;
}
const QString environmentpath = m_environment.value(QString::fromLatin1("PATH"), QString());
return KStandardDirs::findExe(app, environmentpath);
}
void KLauncherAdaptor::sendSIStart() const
{
kDebug() << "sending ASN start";
KStartupInfo::sendStartup(m_kstartupinfoid, m_kstartupinfodata);
}
void KLauncherAdaptor::sendSIUpdate()
{
if (m_kstartupinfoid.none()) {
return;
}
kDebug() << "sending ASN update";
KStartupInfo::sendChange(m_kstartupinfoid, m_kstartupinfodata);
}
void KLauncherAdaptor::sendSIFinish()
{
if (m_kstartupinfoid.none()) {
return;
}
kDebug() << "sending ASN finish";
KStartupInfo::sendFinish(m_kstartupinfoid, m_kstartupinfodata);
m_kstartupinfoid = KStartupInfoId();
m_kstartupinfodata = KStartupInfoData();
} }
#include "moc_klauncher_adaptor.cpp" #include "moc_klauncher_adaptor.cpp"

View file

@ -1,47 +1,47 @@
/* /* This file is part of the KDE libraries
* Copyright 2006, 2007 Thiago Macieira <thiago@kde.org> Copyright (C) 2022 Ivailo Monev <xakepa10@gmail.com>
* Copyright 2006-2008 David Faure <faure@kde.org>
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) version 3, or any
* later version accepted by the membership of KDE e.V. (or its
* successor approved by the membership of KDE e.V.), which shall
* act as a proxy defined in Section 6 of version 3 of the license.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library. If not, see <http://www.gnu.org/licenses/>.
*
*/
#ifndef KLAUNCHER_ADAPTOR_H_18181148166088 This library is free software; you can redistribute it and/or
#define KLAUNCHER_ADAPTOR_H_18181148166088 modify it under the terms of the GNU Library General Public
License version 2, as published by the Free Software Foundation.
#include <QtCore/QObject> This library is distributed in the hope that it will be useful,
#include <QtDBus/QDBusAbstractAdaptor> but WITHOUT ANY WARRANTY; without even the implied warranty of
#include <QtDBus/QDBusMessage> MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Library General Public License for more details.
#include <QList> You should have received a copy of the GNU Library General Public License
#include <QMap> along with this library; see the file COPYING.LIB. If not, write to
#include <QString> the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
#include <QStringList> Boston, MA 02110-1301, USA.
*/
/* #ifndef KLAUNCHER_ADAPTOR_H
* Adaptor class for interface org.kde.KLauncher #define KLAUNCHER_ADAPTOR_H
*/
#include "kstartupinfo.h"
#include <QDBusAbstractAdaptor>
#include <QDBusMessage>
#include <QProcess>
// Adaptor class for interface org.kde.KLauncher
class KLauncherAdaptor: public QDBusAbstractAdaptor class KLauncherAdaptor: public QDBusAbstractAdaptor
{ {
Q_OBJECT Q_OBJECT
Q_CLASSINFO("D-Bus Interface", "org.kde.KLauncher") Q_CLASSINFO("D-Bus Interface", "org.kde.KLauncher")
public: public:
enum KLauncherError {
NoError = 0,
ServiceError = 1,
FindError = 2,
ArgumentsError = 3,
ExecError = 4,
DBusError = 5
};
KLauncherAdaptor(QObject *parent); KLauncherAdaptor(QObject *parent);
virtual ~KLauncherAdaptor(); ~KLauncherAdaptor();
public: // PROPERTIES public: // PROPERTIES
public Q_SLOTS: // METHODS public Q_SLOTS: // METHODS
@ -51,18 +51,30 @@ public Q_SLOTS: // METHODS
int kdeinit_exec_wait(const QString &app, const QStringList &args, const QStringList &env, const QString& startup_id, const QDBusMessage &msg, QString &dbusServiceName, QString &error, qint64 &pid); int kdeinit_exec_wait(const QString &app, const QStringList &args, const QStringList &env, const QString& startup_id, const QDBusMessage &msg, QString &dbusServiceName, QString &error, qint64 &pid);
int kdeinit_exec_with_workdir(const QString &app, const QStringList &args, const QString& workdir, const QStringList &env, const QString& startup_id, const QDBusMessage &msg, QString &dbusServiceName, QString &error, qint64 &pid); int kdeinit_exec_with_workdir(const QString &app, const QStringList &args, const QString& workdir, const QStringList &env, const QString& startup_id, const QDBusMessage &msg, QString &dbusServiceName, QString &error, qint64 &pid);
void reparseConfiguration(); void reparseConfiguration();
qint64 requestHoldSlave(const QString &url, const QString &app_socket);
qint64 requestSlave(const QString &protocol, const QString &host, const QString &app_socket, QString &error);
bool checkForHeldSlave (const QString &url);
void setLaunchEnv(const QString &name, const QString &value); void setLaunchEnv(const QString &name, const QString &value);
int start_service_by_desktop_name(const QString &serviceName, const QStringList &urls, const QStringList &envs, const QString &startup_id, bool blind, const QDBusMessage &msg, QString &dbusServiceName, QString &error, qint64 &pid); int start_service_by_desktop_name(const QString &serviceName, const QStringList &urls, const QStringList &envs, const QString &startup_id, bool blind, const QDBusMessage &msg, QString &dbusServiceName, QString &error, qint64 &pid);
int start_service_by_desktop_path(const QString &serviceName, const QStringList &urls, const QStringList &envs, const QString &startup_id, bool blind, const QDBusMessage &msg, QString &dbusServiceName, QString &error, qint64 &pid); int start_service_by_desktop_path(const QString &serviceName, const QStringList &urls, const QStringList &envs, const QString &startup_id, bool blind, const QDBusMessage &msg, QString &dbusServiceName, QString &error, qint64 &pid);
void waitForSlave(qint64 pid, const QDBusMessage &msg);
void terminate_kdeinit();
Q_SIGNALS: // SIGNALS Q_SIGNALS: // SIGNALS
void autoStart0Done(); void autoStart0Done();
void autoStart1Done(); void autoStart1Done();
void autoStart2Done(); void autoStart2Done();
private Q_SLOTS:
void slotProcessStateChanged(QProcess::ProcessState state);
void slotProcessFinished(int exitcode);
private:
QString findExe(const QString &app) const;
void sendSIStart() const;
void sendSIUpdate();
void sendSIFinish();
KStartupInfoId m_kstartupinfoid;
KStartupInfoData m_kstartupinfodata;
QProcessEnvironment m_environment;
QList<QProcess*> m_processes;
QStringList m_autostart;
}; };
#endif #endif // KLAUNCHER_ADAPTOR_H

View file

@ -1,45 +0,0 @@
/*
* Copyright 2009 David Faure <faure@kde.org>
*
* This library is free software; you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation; either version 2 of the License or ( at
* your option ) version 3 or, at the discretion of KDE e.V. ( which shall
* act as a proxy as in section 14 of the GPLv3 ), any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Library General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this library; see the file COPYING.LIB. If not, write to
* the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
* Boston, MA 02110-1301, USA.
*/
#include "klauncher_cmds.h"
const char* commandToString(int command)
{
switch (command) {
case LAUNCHER_SETENV:
return "LAUNCHER_SETENV";
case LAUNCHER_CHILD_DIED:
return "LAUNCHER_CHILD_DIED";
case LAUNCHER_OK:
return "LAUNCHER_OK";
case LAUNCHER_ERROR:
return "LAUNCHER_ERROR";
case LAUNCHER_TERMINATE_KDEINIT:
return "LAUNCHER_TERMINATE_KDEINIT";
case LAUNCHER_DEBUG_WAIT:
return "LAUNCHER_DEBUG_WAIT";
case LAUNCHER_EXEC_ASN:
return "LAUNCHER_EXEC_ASN";
case LAUNCHER_EXEC:
return "LAUNCHER_EXEC";
default:
return "UNKNOWN COMMAND";
}
}

View file

@ -1,127 +0,0 @@
/*
This file is part of the KDE libraries
Copyright (c) 1999 Waldo Bastian <bastian@kde.org>
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Library General Public
License version 2 as published by the Free Software Foundation.
This library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Library General Public License for more details.
You should have received a copy of the GNU Library General Public License
along with this library; see the file COPYING.LIB. If not, write to
the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
Boston, MA 02110-1301, USA.
*/
#ifndef _KLAUNCHER_CMDS_H_
#define _KLAUNCHER_CMDS_H_
typedef struct
{
long cmd;
long arg_length;
} klauncher_header;
/* Launcher commands: */
/*
* LAUNCHER_SETENV
*
* Change environment of future processes launched via kdeinit.
* DON'T use this if you want to change environment only for one
* application you're going to start.
*
* char *env_name;
* char *env_value;
*/
#define LAUNCHER_SETENV 1
/*
* LAUNCHER_CHILD_DIED
*
* Notification A child of kdeinit died.
*
* long pid;
* long exit_code;
*/
#define LAUNCHER_CHILD_DIED 2
/*
* LAUNCHER_OK
*
* Notification Last process launched ok.
*
* long pid;
*/
#define LAUNCHER_OK 3
/*
* LAUNCHER_ERROR
*
* Notification Last process could not be launched.
*
* char *error msg (utf8)
*/
#define LAUNCHER_ERROR 4
/*
* LAUNCHER_TERMINATE_KDEINIT
*
* Suicide is painless
*/
#define LAUNCHER_TERMINATE_KDEINIT 5
/*
* LAUNCHER_DEBUG_WAIT
*
* Next process started will do a sleep(1000000)
* before calling main()/kdemain()
*
* (Used for debugging io-slaves)
*/
#define LAUNCHER_DEBUG_WAIT 6
/*
* LAUNCHER_EXEC_ASN
*
* Start a new process. The given environment variables will
* be added to its environment before starting it.
* Starts app-startup notification.
*
* long argc: number of arguments
* char *args: arguments, argument 0 is the program to start.
* long envc: number of environment vars
* char *envs: environment strings.
* int avoid_loops : avoid using the first path in $PATH where
* this process binary is found in order to avoid
* infinite loop by binary->kdeinit_wrapper link in $PATH
* char* startup_id: app startup notification id, "0" for none,
* "" ( empty string ) is the default
*
*/
#define LAUNCHER_EXEC_ASN 7
/*
* LAUNCHER_EXEC
*
* Start a new process. The given environment variables will be
* added to its environment before starting it.
* There will be no app startup notification.
*
* long argc: number of arguments
* char *args: arguments, argument 0 is the program to start.
* long envc: number of environment vars
* char *envs: environment strings.
* int avoid_loops : avoid using the first path in $PATH where
* this process binary is found in order to avoid
* infinite loop by binary->kdeinit_wrapper link in $PATH
*/
#define LAUNCHER_EXEC 8
const char* commandToString(int command);
#endif

View file

@ -1,118 +0,0 @@
/*
This file is part of the KDE libraries
Copyright (c) 1999 Waldo Bastian <bastian@kde.org>
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Library General Public
License version 2 as published by the Free Software Foundation.
This library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Library General Public License for more details.
You should have received a copy of the GNU Library General Public License
along with this library; see the file COPYING.LIB. If not, write to
the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
Boston, MA 02110-1301, USA.
*/
#include <config.h>
#include <unistd.h>
#include <fcntl.h>
#include "klauncher.h"
#include <kcomponentdata.h>
#include "kcrash.h"
#include "kdebug.h"
#include <stdio.h>
#include <stdlib.h>
#include <signal.h>
#include <klocale.h>
#include <kde_file.h>
#include "klauncher_cmds.h"
#include <QtCore/QCoreApplication>
static int sigpipe[ 2 ];
static void sig_handler(int sig_num)
{
// No recursion
KDE_signal( SIGHUP, SIG_IGN);
KDE_signal( SIGTERM, SIG_IGN);
fprintf(stderr, "klauncher: Exiting on signal %d\n", sig_num);
char tmp = 'x';
write( sigpipe[ 1 ], &tmp, 1 );
}
int main( int argc, char**argv )
{
// Started via kdeinit.
int launcherFd;
if (argc != 2 || memcmp(argv[1], "--fd=", 5) || !(launcherFd = atoi(argv[1] + 5)))
{
fprintf(stderr, "%s", i18n("klauncher: This program is not supposed to be started manually.\n"
"klauncher: It is started automatically by kdeinit4.\n").toLocal8Bit().data());
return 1;
}
KComponentData componentData("klauncher", "kdelibs4");
KGlobal::locale();
// WABA: Make sure not to enable session management.
putenv(strdup("SESSION_MANAGER="));
// We need a QCoreApplication to get a DBus event loop
QCoreApplication app(argc, argv);
app.setApplicationName( componentData.componentName() );
int maxTry = 3;
while(true)
{
QString service(QLatin1String("org.kde.klauncher")); // same as ktoolinvocation.cpp
if (!QDBusConnection::sessionBus().isConnected()) {
kWarning() << "No DBUS session-bus found. Check if you have started the DBUS server.";
return 1;
}
QDBusReply<QDBusConnectionInterface::RegisterServiceReply> reply =
QDBusConnection::sessionBus().interface()->registerService(service);
if (!reply.isValid())
{
kWarning() << "DBUS communication problem!";
return 1;
}
if (reply == QDBusConnectionInterface::ServiceRegistered)
break;
if (--maxTry == 0)
{
kWarning() << "Another instance of klauncher is already running!";
return 1;
}
// Wait a bit...
kWarning() << "Waiting for already running klauncher to exit.";
sleep(1);
// Try again...
}
KLauncher *launcher = new KLauncher(launcherFd);
QDBusConnection::sessionBus().registerObject(QString::fromLatin1("/"), launcher);
if (pipe(sigpipe) != 0) {
perror("klauncher: pipe failed.");
return 1;
}
QSocketNotifier* signotif = new QSocketNotifier( sigpipe[ 0 ], QSocketNotifier::Read, launcher );
QObject::connect( signotif, SIGNAL(activated(int)), launcher, SLOT(destruct()));
KCrash::setEmergencySaveFunction(sig_handler);
KDE_signal( SIGHUP, sig_handler);
KDE_signal( SIGPIPE, SIG_IGN);
KDE_signal( SIGTERM, sig_handler);
return app.exec();
}

View file

@ -0,0 +1,3 @@
[D-BUS Service]
Name=org.kde.klauncher
Exec=@KDE4_BIN_INSTALL_DIR@/klauncher4

View file

@ -1,89 +0,0 @@
/*
* ProFTPD - FTP server daemon
* Copyright (c) 2007 The ProFTPD Project team //krazy:exclude=copyright
* Copyright (c) 2007 Alex Merry <alex.merry@kdemail.net>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the
* Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
* Boston, MA 02110-1301 USA
*/
#include "proctitle.h"
#include "config-kdeinit.h"
#include <string.h>
#include <stdio.h>
#include <stdarg.h>
#include <stdlib.h>
#ifdef HAVE_SETPROCTITLE
# define PF_ARGV_TYPE PF_ARGV_NONE
# include <sys/types.h>
# include <unistd.h>
#endif /* HAVE_SETPROCTITLE */
#ifdef HAVE___PROGNAME
extern char *__progname;
#endif /* HAVE___PROGNAME */
#ifdef HAVE___PROGNAME_FULL
extern char *__progname_full;
#endif /* HAVE___PROGNAME_FULL */
/**
* Set up the memory space for setting the proctitle
*/
void proctitle_init(int argc, char *argv[]) {
# ifdef HAVE___PROGNAME
/* Set the __progname variable so glibc and company
* don't go nuts.
*/
__progname = strdup("kdeinit4");
# endif /* HAVE___PROGNAME */
# ifdef HAVE___PROGNAME_FULL
/* __progname_full too */
__progname_full = strdup(argv[0]);
# endif /* HAVE___PROGNAME_FULL */
}
void proctitle_set(const char *fmt, ...) {
va_list msg;
if ( !fmt ) {
return;
}
va_start(msg, fmt);
#ifdef HAVE_SETPROCTITLE
char statbuf[BUFSIZ];
memset(statbuf, 0, sizeof(statbuf));
# if __FreeBSD__ >= 4 && !defined(FREEBSD4_0) && !defined(FREEBSD4_1)
/* FreeBSD's setproctitle() automatically prepends the process name. */
vsnprintf(statbuf, sizeof(statbuf), fmt, msg);
# else /* FREEBSD4 */
/* Manually append the process name for non-FreeBSD platforms. */
snprintf(statbuf, sizeof(statbuf), "%s", "kdeinit4: ");
vsnprintf(statbuf + strlen(statbuf),
sizeof(statbuf) - strlen(statbuf),
fmt,
msg);
# endif /* FREEBSD4 */
setproctitle("%s", statbuf);
#endif /* HAVE_SETPROCTITLE */
va_end(msg);
}

View file

@ -1,47 +0,0 @@
/*
* ProFTPD - FTP server daemon
* Copyright (c) 2007 The ProFTPD Project team //krazy:exclude=copyright
* Copyright (c) 2007 Alex Merry <alex.merry@kdemail.net>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the
* Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
* Boston, MA 02110-1301 USA
*/
#ifndef PROCTITLE_H
#define PROCTITLE_H
/**
* Initialises the program data variables to allow the
* changing of the process title. This _must_ be called
* before proctitle_set, and must only be called once.
*
* @param argc argc, as passed to main()
* @param argv argv, as passed to main()
*/
void proctitle_init(int argc, char *argv[]);
/**
* Change the process title. It accepts a variable number
* of arguments (a va_list) in the manner of the printf
* family of functions. See the documentation for
* printf for a description of the format string.
*/
void proctitle_set(const char *fmt, ...)
#if !defined(__INSURE__)
__attribute__ (( format ( printf, 1, 2 ) ) )
#endif
;
#endif /* PROCTITLE_H */

View file

@ -38,7 +38,6 @@
#include <kglobal.h> #include <kglobal.h>
#include <kstandarddirs.h> #include <kstandarddirs.h>
#include <ktoolinvocation.h> #include <ktoolinvocation.h>
#include <klauncher_iface.h>
#include "kservice.h" #include "kservice.h"
#include <kio/global.h> #include <kio/global.h>
@ -300,10 +299,6 @@ void Slave::hold(const KUrl &url)
emit slaveDied(this); emit slaveDied(this);
} }
deref(); deref();
// Call KLauncher::waitForSlave(pid);
{
KToolInvocation::klauncher()->waitForSlave(d->m_pid);
}
} }
void Slave::suspend() void Slave::suspend()
@ -402,95 +397,41 @@ Slave* Slave::createSlave( const QString &protocol, const KUrl& url, int& error,
Slave *slave = new Slave(protocol); Slave *slave = new Slave(protocol);
QString slaveAddress = slave->d_func()->slaveconnserver->address(); QString slaveAddress = slave->d_func()->slaveconnserver->address();
#ifdef Q_OS_UNIX QString _name = KProtocolInfo::exec(protocol);
// In such case we start the slave via QProcess. if (_name.isEmpty())
// It's possible to force this by setting the env. variable
// KDE_FORK_SLAVES, Clearcase seems to require this.
static bool bForkSlaves = !qgetenv("KDE_FORK_SLAVES").isEmpty();
if (!bForkSlaves)
{ {
// check the UID of klauncher error_text = i18n("Unknown protocol '%1'.", protocol);
QDBusReply<uint> reply = QDBusConnection::sessionBus().interface()->serviceUid(KToolInvocation::klauncher()->service());
if (reply.isValid() && getuid() != reply)
bForkSlaves = true;
}
if (bForkSlaves)
{
QString _name = KProtocolInfo::exec(protocol);
if (_name.isEmpty())
{
error_text = i18n("Unknown protocol '%1'.", protocol);
error = KIO::ERR_CANNOT_LAUNCH_PROCESS;
delete slave;
return 0;
}
KPluginLoader lib(_name, KGlobal::mainComponent());
QString lib_path = lib.fileName();
if (lib_path.isEmpty())
{
error_text = i18n("Can not find io-slave for protocol '%1'.", protocol);
error = KIO::ERR_CANNOT_LAUNCH_PROCESS;
delete slave;
return 0;
}
const QStringList args = QStringList() << lib_path << protocol << "" << slaveAddress;
kDebug() << "kioslave" << ", " << lib_path << ", " << protocol << ", " << QString() << ", " << slaveAddress;
QProcess::startDetached( KStandardDirs::findExe("kioslave"), args );
return slave;
}
#endif
org::kde::KLauncher* klauncher = KToolInvocation::klauncher();
QString errorStr;
QDBusReply<qint64> reply = klauncher->requestSlave(protocol, url.host(), slaveAddress, errorStr);
if (!reply.isValid()) {
error_text = i18n("Cannot talk to klauncher: %1", klauncher->lastError().message() );
error = KIO::ERR_CANNOT_LAUNCH_PROCESS; error = KIO::ERR_CANNOT_LAUNCH_PROCESS;
delete slave; delete slave;
return 0; return 0;
} }
pid_t pid = reply; KPluginLoader lib(_name, KGlobal::mainComponent());
if (!pid) QString lib_path = lib.fileName();
if (lib_path.isEmpty())
{ {
error_text = i18n("Unable to create io-slave:\nklauncher said: %1", errorStr); error_text = i18n("Can not find io-slave for protocol '%1'.", protocol);
error = KIO::ERR_CANNOT_LAUNCH_PROCESS; error = KIO::ERR_CANNOT_LAUNCH_PROCESS;
delete slave; delete slave;
return 0; return 0;
} }
slave->setPID(pid);
QTimer::singleShot(1000*SLAVE_CONNECTION_TIMEOUT_MIN, slave, SLOT(timeout())); const QStringList args = QStringList() << lib_path << protocol << "" << slaveAddress;
kDebug() << "kioslave" << ", " << lib_path << ", " << protocol << ", " << QString() << ", " << slaveAddress;
QProcess::startDetached( KStandardDirs::findExe("kioslave"), args );
return slave; return slave;
} }
Slave* Slave::holdSlave( const QString &protocol, const KUrl& url ) Slave* Slave::holdSlave( const QString &protocol, const KUrl& url )
{ {
//kDebug(7002) << "holdSlave" << protocol << "for" << url; //kDebug(7002) << "holdSlave" << protocol << "for" << url;
Slave *slave = new Slave(protocol); return 0;
QString slaveAddress = slave->d_func()->slaveconnserver->address();
QDBusReply<qint64> reply = KToolInvocation::klauncher()->requestHoldSlave(url.url(), slaveAddress);
if (!reply.isValid()) {
delete slave;
return 0;
}
pid_t pid = reply;
if (!pid)
{
delete slave;
return 0;
}
slave->setPID(pid);
QTimer::singleShot(1000*SLAVE_CONNECTION_TIMEOUT_MIN, slave, SLOT(timeout()));
return slave;
} }
bool Slave::checkForHeldSlave(const KUrl &url) bool Slave::checkForHeldSlave(const KUrl &url)
{ {
return KToolInvocation::klauncher()->checkForHeldSlave(url.url()); return false;
} }
#include "moc_slave.cpp" #include "moc_slave.cpp"

View file

@ -155,9 +155,9 @@ void KRunUnitTest::testProcessDesktopExecNoFile_data()
KUrl::List l4; l4 << KUrl( "http://login:password@www.kde.org" ); KUrl::List l4; l4 << KUrl( "http://login:password@www.kde.org" );
// A real-world use case would be kate. // A real-world use case would be kate.
// But I picked kdeinit4 since it's installed by kdelibs // But I picked klauncher4 since it's installed by kdelibs
QString kdeinit = KStandardDirs::findExe("kdeinit4"); QString klauncher = KStandardDirs::findExe("klauncher4");
if (kdeinit.isEmpty()) kdeinit = "kdeinit4"; if (klauncher.isEmpty()) klauncher = "klauncher4";
QString kioexec = KStandardDirs::findExe("kioexec"); QString kioexec = KStandardDirs::findExe("kioexec");
if (kioexec.isEmpty()) if (kioexec.isEmpty())
@ -165,30 +165,30 @@ void KRunUnitTest::testProcessDesktopExecNoFile_data()
QString kmailservice = KStandardDirs::findExe("kmailservice"); QString kmailservice = KStandardDirs::findExe("kmailservice");
if (kmailservice.isEmpty()) kmailservice = "kmailservice"; if (kmailservice.isEmpty()) kmailservice = "kmailservice";
if (!kdeinit.isEmpty()) { if (!klauncher.isEmpty()) {
QVERIFY(!kmailservice.isEmpty()); QVERIFY(!kmailservice.isEmpty());
} }
// NOTE: using QString() for concats to avoid QStringBuilder metatype, which is not valid // NOTE: using QString() for concats to avoid QStringBuilder metatype, which is not valid
QTest::newRow("%U l0") << "kdeinit4 %U" << l0 << false << kdeinit; QTest::newRow("%U l0") << "klauncher4 %U" << l0 << false << klauncher;
QTest::newRow("%U l1") << "kdeinit4 %U" << l1 << false << QString(kdeinit + " /tmp"); QTest::newRow("%U l1") << "klauncher4 %U" << l1 << false << QString(klauncher + " /tmp");
QTest::newRow("%U l2") << "kdeinit4 %U" << l2 << false << QString(kdeinit + " http://localhost/foo"); QTest::newRow("%U l2") << "klauncher4 %U" << l2 << false << QString(klauncher + " http://localhost/foo");
QTest::newRow("%U l3") << "kdeinit4 %U" << l3 << false << QString(kdeinit + " /local/file http://remotehost.org/bar"); QTest::newRow("%U l3") << "klauncher4 %U" << l3 << false << QString(klauncher + " /local/file http://remotehost.org/bar");
//QTest::newRow("%u l0") << "kdeinit4 %u" << l0 << false << kdeinit; // gives runtime warning //QTest::newRow("%u l0") << "klauncher4 %u" << l0 << false << klauncher; // gives runtime warning
QTest::newRow("%u l1") << "kdeinit4 %u" << l1 << false << QString(kdeinit + " /tmp"); QTest::newRow("%u l1") << "klauncher4 %u" << l1 << false << QString(klauncher + " /tmp");
QTest::newRow("%u l2") << "kdeinit4 %u" << l2 << false << QString(kdeinit + " http://localhost/foo"); QTest::newRow("%u l2") << "klauncher4 %u" << l2 << false << QString(klauncher + " http://localhost/foo");
//QTest::newRow("%u l3") << "kdeinit4 %u" << l3 << false << kdeinit; // gives runtime warning //QTest::newRow("%u l3") << "klauncher4 %u" << l3 << false << klauncher; // gives runtime warning
QTest::newRow("%F l0") << "kdeinit4 %F" << l0 << false << kdeinit; QTest::newRow("%F l0") << "klauncher4 %F" << l0 << false << klauncher;
QTest::newRow("%F l1") << "kdeinit4 %F" << l1 << false << QString(kdeinit + " /tmp"); QTest::newRow("%F l1") << "klauncher4 %F" << l1 << false << QString(klauncher + " /tmp");
QTest::newRow("%F l2") << "kdeinit4 %F" << l2 << false << QString(kioexec + " 'kdeinit4 %F' http://localhost/foo"); QTest::newRow("%F l2") << "klauncher4 %F" << l2 << false << QString(kioexec + " 'klauncher4 %F' http://localhost/foo");
QTest::newRow("%F l3") << "kdeinit4 %F" << l3 << false << QString(kioexec + " 'kdeinit4 %F' file:///local/file http://remotehost.org/bar"); QTest::newRow("%F l3") << "klauncher4 %F" << l3 << false << QString(kioexec + " 'klauncher4 %F' file:///local/file http://remotehost.org/bar");
QTest::newRow("%F l1 tempfile") << "kdeinit4 %F" << l1 << true << QString(kioexec + " --tempfiles 'kdeinit4 %F' file:///tmp"); QTest::newRow("%F l1 tempfile") << "klauncher4 %F" << l1 << true << QString(kioexec + " --tempfiles 'klauncher4 %F' file:///tmp");
QTest::newRow("sh -c kdeinit4 %F") << "sh -c \"kdeinit4 \"'\\\"'\"%F\"'\\\"'" QTest::newRow("sh -c klauncher4 %F") << "sh -c \"klauncher4 \"'\\\"'\"%F\"'\\\"'"
<< l1 << false << QString(m_sh + " -c 'kdeinit4 \\\"/tmp\\\"'"); << l1 << false << QString(m_sh + " -c 'klauncher4 \\\"/tmp\\\"'");
QTest::newRow("kmailservice %u l1") << "kmailservice %u" << l1 << false << QString(kmailservice + " /tmp"); QTest::newRow("kmailservice %u l1") << "kmailservice %u" << l1 << false << QString(kmailservice + " /tmp");
QTest::newRow("kmailservice %u l4") << "kmailservice %u" << l4 << false << QString(kmailservice + " http://login:password@www.kde.org"); QTest::newRow("kmailservice %u l4") << "kmailservice %u" << l4 << false << QString(kmailservice + " http://login:password@www.kde.org");