mirror of
https://bitbucket.org/smil3y/kdelibs.git
synced 2025-02-23 10:22:48 +00:00
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:
parent
e851a35ee5
commit
aa6b5ea4f0
27 changed files with 704 additions and 4690 deletions
|
@ -57,8 +57,6 @@ check_function_exists(fdatasync HAVE_FDATASYNC) # kd
|
|||
check_function_exists(arc4random_uniform HAVE_ARC4RANDOM_UNIFORM) # kdecore
|
||||
check_function_exists(sendfile HAVE_SENDFILE) # kioslave
|
||||
|
||||
check_library_exists(socket connect "" HAVE_SOCKET_LIBRARY) # kinit
|
||||
|
||||
if (UNIX)
|
||||
# for kpty
|
||||
check_include_files("sys/types.h;libutil.h" HAVE_LIBUTIL_H)
|
||||
|
|
|
@ -42,6 +42,7 @@
|
|||
940 kmediaplayer
|
||||
1000 kparts
|
||||
1209 libplasma
|
||||
1210 klauncher4
|
||||
7000 kio
|
||||
7001 kio (KDirWatch)
|
||||
7002 kio (Slave)
|
||||
|
@ -54,7 +55,6 @@
|
|||
7011 kdecore (KSycoca)
|
||||
7014 kdecore (trader)
|
||||
7015 kio (KAutoMount)
|
||||
7016 kio (KLauncher)
|
||||
7017 kio (KIOConnection)
|
||||
7019 kio (kioslave)
|
||||
7020 kded4
|
||||
|
|
|
@ -59,18 +59,13 @@ KToolInvocation::~KToolInvocation()
|
|||
|
||||
org::kde::KLauncher *KToolInvocation::klauncher()
|
||||
{
|
||||
if (!QDBusConnection::sessionBus().interface()->isServiceRegistered(QString::fromLatin1("org.kde.klauncher"))) {
|
||||
kDebug(180) << "klauncher not running... launching kdeinit";
|
||||
// Try to launch kdeinit.
|
||||
QString srv = KStandardDirs::findExe(QLatin1String("kdeinit4"));
|
||||
if (srv.isEmpty()) {
|
||||
kError() << "kdeinit4 not available";
|
||||
// NOTE: this will crash users not checking the pointer
|
||||
return nullptr;
|
||||
}
|
||||
QStringList args;
|
||||
args += QString::fromLatin1("--suicide");
|
||||
QProcess::execute(srv, args);
|
||||
// If klauncher is not running we need to launch it
|
||||
static const QString klauncherInterface = QString::fromLatin1("org.kde.klauncher");
|
||||
QDBusConnectionInterface* sessionInterface = QDBusConnection::sessionBus().interface();
|
||||
const bool klauncherRunning = sessionInterface->isServiceRegistered(klauncherInterface);
|
||||
if (!klauncherRunning) {
|
||||
kDebug(7011) << "Launching klauncher";
|
||||
sessionInterface->startService(klauncherInterface);
|
||||
}
|
||||
return self()->klauncherIface;
|
||||
}
|
||||
|
|
|
@ -205,23 +205,23 @@ void KStandarddirsTest::testFindExe()
|
|||
QSKIP( "kdelibs not installed", SkipAll );
|
||||
|
||||
// findExe with a result in bin
|
||||
const QString kdeinit = KGlobal::dirs()->findExe( "kdeinit4" );
|
||||
QVERIFY( !kdeinit.isEmpty() );
|
||||
QVERIFY2(kdeinit.endsWith("bin/kdeinit4" EXT, PATH_SENSITIVITY), qPrintable(kdeinit));
|
||||
const QString klauncher = KGlobal::dirs()->findExe( "klauncher4" );
|
||||
QVERIFY( !klauncher.isEmpty() );
|
||||
QVERIFY2(klauncher.endsWith("bin/klauncher4" EXT, PATH_SENSITIVITY), qPrintable(klauncher));
|
||||
|
||||
// Check the "exe" resource too
|
||||
QString kdeinitexe = KGlobal::dirs()->locate( "exe", "kdeinit4" );
|
||||
QVERIFY2(kdeinitexe.endsWith("bin/kdeinit4" EXT, PATH_SENSITIVITY), qPrintable(kdeinit));
|
||||
QString klauncherexe = KGlobal::dirs()->locate( "exe", "klauncher4" );
|
||||
QVERIFY2(klauncherexe.endsWith("bin/klauncher4" EXT, PATH_SENSITIVITY), qPrintable(klauncherexe));
|
||||
|
||||
#ifdef Q_OS_UNIX
|
||||
// findExe with a result in libexec
|
||||
const QString klauncher = KGlobal::dirs()->findExe( "klauncher" );
|
||||
QVERIFY( !klauncher.isEmpty() );
|
||||
QVERIFY( klauncher.endsWith("/klauncher" EXT, PATH_SENSITIVITY ) );
|
||||
const QString kioslave = KGlobal::dirs()->findExe( "kioslave" );
|
||||
QVERIFY( !kioslave.isEmpty() );
|
||||
QVERIFY( kioslave.endsWith("/kioslave" EXT, PATH_SENSITIVITY ) );
|
||||
|
||||
// locate("exe") with a result in libexec
|
||||
const QString locateExeResult = KGlobal::dirs()->locate("exe", "klauncher");
|
||||
QVERIFY(locateExeResult.endsWith("/klauncher" EXT, PATH_SENSITIVITY));
|
||||
const QString locateExeResult = KGlobal::dirs()->locate("exe", "kioslave");
|
||||
QVERIFY(locateExeResult.endsWith("/kioslave" EXT, PATH_SENSITIVITY));
|
||||
|
||||
// findExe with relative path
|
||||
const QString pwd = QDir::currentPath();
|
||||
|
|
|
@ -100,24 +100,6 @@ public Q_SLOTS: // METHODS
|
|||
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)
|
||||
{
|
||||
QList<QVariant> argumentList;
|
||||
|
@ -151,20 +133,6 @@ public Q_SLOTS: // METHODS
|
|||
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
|
||||
void autoStart0Done();
|
||||
void autoStart1Done();
|
||||
|
|
|
@ -51,12 +51,14 @@
|
|||
#include <kaboutdata.h>
|
||||
#include <kcmdlineargs.h>
|
||||
#ifndef KBUILDSYCOCA_NO_KCRASH
|
||||
#include <kde_file.h>
|
||||
#include <kcrash.h>
|
||||
#endif
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <unistd.h>
|
||||
#include <time.h>
|
||||
#include <signal.h>
|
||||
|
||||
typedef QHash<QString, KSycocaEntry::Ptr> KBSEntryDict;
|
||||
typedef QList<KSycocaEntry::List> KSycocaEntryListList;
|
||||
|
@ -81,12 +83,16 @@ static QByteArray g_sycocaPath = 0;
|
|||
static bool bGlobalDatabase = false;
|
||||
static bool bMenuTest = false;
|
||||
|
||||
void crashHandler(int)
|
||||
void crashHandler(int sig)
|
||||
{
|
||||
// If we crash while reading sycoca, we delete the database
|
||||
// in an attempt to recover.
|
||||
if (!g_sycocaPath.isEmpty())
|
||||
unlink(g_sycocaPath.constData());
|
||||
KDE_signal(sig, SIG_DFL);
|
||||
|
||||
// If we crash while reading sycoca, we delete the database in an attempt to recover.
|
||||
if (!g_sycocaPath.isEmpty()) {
|
||||
unlink(g_sycocaPath.constData());
|
||||
}
|
||||
|
||||
::exit(sig);
|
||||
}
|
||||
|
||||
static QString sycocaPath()
|
||||
|
@ -641,9 +647,7 @@ int main(int argc, char **argv)
|
|||
KComponentData mainComponent(d);
|
||||
|
||||
#ifndef KBUILDSYCOCA_NO_KCRASH
|
||||
KCrash::setCrashHandler(KCrash::defaultCrashHandler);
|
||||
KCrash::setEmergencySaveFunction(crashHandler);
|
||||
KCrash::setApplicationName(QString(appName));
|
||||
KCrash::setCrashHandler(crashHandler);
|
||||
#endif
|
||||
|
||||
// force generating of KLocale object. if not, the database will get
|
||||
|
|
|
@ -79,7 +79,6 @@
|
|||
#endif
|
||||
|
||||
KApplication* KApplication::KApp = 0L;
|
||||
bool KApplication::loadedByKdeinit = false;
|
||||
|
||||
#ifdef Q_WS_X11
|
||||
static Atom atom_DesktopWindow = None;
|
||||
|
@ -666,12 +665,7 @@ void KApplicationPrivate::parseCommandLine( )
|
|||
if (qgetenv("KDE_DEBUG").isEmpty() && args->isSet("crashhandler"))
|
||||
{
|
||||
// enable drkonqi
|
||||
KCrash::setDrKonqiEnabled(true);
|
||||
}
|
||||
// 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());
|
||||
KCrash::setFlags(KCrash::flags() | KCrash::DrKonqi);
|
||||
}
|
||||
|
||||
#ifdef Q_WS_X11
|
||||
|
|
|
@ -263,11 +263,6 @@ public:
|
|||
bool notify( QObject* receiver, QEvent* event );
|
||||
#endif // Q_WS_X11
|
||||
|
||||
/**
|
||||
* @internal
|
||||
*/
|
||||
static bool loadedByKdeinit;
|
||||
|
||||
public Q_SLOTS:
|
||||
/**
|
||||
* Updates the last user action timestamp to the given time, or to the current time,
|
||||
|
|
|
@ -1,710 +1,157 @@
|
|||
/*
|
||||
* This file is part of the KDE Libraries
|
||||
* Copyright (C) 2000 Timo Hummel <timo.hummel@sap.com>
|
||||
* Tom Braun <braunt@fh-konstanz.de>
|
||||
* Copyright 2009 KDE e.V.
|
||||
* By Adriaan de Groot <groot@kde.org>
|
||||
* Copyright (C) 2010 George Kiagiadakis <kiagiadakis.george@gmail.com>
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Library General Public
|
||||
* 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
|
||||
* 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.
|
||||
*/
|
||||
/* This file is part of the KDE libraries
|
||||
Copyright (C) 2022 Ivailo Monev <xakepa10@gmail.com>
|
||||
|
||||
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 "kcrash.h"
|
||||
#include <kcmdlineargs.h>
|
||||
#include <kstandarddirs.h>
|
||||
#include <config-kstandarddirs.h>
|
||||
#include "kcmdlineargs.h"
|
||||
#include "kde_file.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 <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>
|
||||
#endif
|
||||
#include "fixx11h.h"
|
||||
|
||||
#ifdef Q_OS_SOLARIS
|
||||
// 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::HandlerType s_crashHandler = nullptr;
|
||||
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
|
||||
signal (SIGSEGV, handler);
|
||||
sigaddset(&mask, SIGSEGV);
|
||||
SIGSEGV,
|
||||
#endif
|
||||
#ifdef SIGBUS
|
||||
signal (SIGBUS, handler);
|
||||
sigaddset(&mask, SIGBUS);
|
||||
SIGBUS,
|
||||
#endif
|
||||
#ifdef SIGFPE
|
||||
signal (SIGFPE, handler);
|
||||
sigaddset(&mask, SIGFPE);
|
||||
SIGFPE,
|
||||
#endif
|
||||
#ifdef SIGILL
|
||||
signal (SIGILL, handler);
|
||||
sigaddset(&mask, SIGILL);
|
||||
SIGILL,
|
||||
#endif
|
||||
#ifdef SIGABRT
|
||||
signal (SIGABRT, handler);
|
||||
sigaddset(&mask, SIGABRT);
|
||||
SIGABRT,
|
||||
#endif
|
||||
0
|
||||
};
|
||||
|
||||
sigprocmask(SIG_UNBLOCK, &mask, 0);
|
||||
|
||||
s_crashHandler = handler;
|
||||
void KCrash::setFlags(KCrash::CrashFlags flags)
|
||||
{
|
||||
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::crashHandler()
|
||||
KCrash::CrashFlags KCrash::flags()
|
||||
{
|
||||
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;
|
||||
}
|
||||
|
||||
static void
|
||||
closeAllFDs()
|
||||
void KCrash::defaultCrashHandler(int sig)
|
||||
{
|
||||
// Close all remaining file descriptors except for stdin/stdout/stderr
|
||||
struct rlimit rlp;
|
||||
getrlimit(RLIMIT_NOFILE, &rlp);
|
||||
for (int i = 3; i < (int)rlp.rlim_cur; i++)
|
||||
close(i);
|
||||
}
|
||||
KDE_signal(sig, SIG_DFL);
|
||||
|
||||
void
|
||||
KCrash::defaultCrashHandler (int sig)
|
||||
{
|
||||
// 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. */);
|
||||
#if 0
|
||||
kFatal() << QCoreApplication::applicationName() << "crashed" << "(" << QCoreApplication::applicationPid() << ")";
|
||||
return;
|
||||
#endif
|
||||
|
||||
if (crashRecursionCounter < 2) {
|
||||
if (s_emergencySaveFunction) {
|
||||
s_emergencySaveFunction (sig);
|
||||
}
|
||||
if ((s_flags & AutoRestart) && s_autoRestartCommand) {
|
||||
sleep(1);
|
||||
startProcess(s_autoRestartArgc, const_cast<const char**>(s_autoRestartCommandLine), false);
|
||||
}
|
||||
crashRecursionCounter++;
|
||||
}
|
||||
if (s_flags & KCrash::AutoRestart) {
|
||||
QStringList args;
|
||||
|
||||
// Note: KCrash closes FDs unconditionally later on if it forks to Dr Konqi
|
||||
// and this program's FDs do not matter if kdeinit starts Dr Konqi.
|
||||
if (!(s_flags & KeepFDs))
|
||||
closeAllFDs();
|
||||
# if defined(Q_WS_X11)
|
||||
else if (QX11Info::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]);
|
||||
// start up on the correct display
|
||||
args.append(QString::fromLatin1("-display"));
|
||||
if (QX11Info::display()) {
|
||||
args.append(XDisplayString(QX11Info::display()));
|
||||
} else {
|
||||
args.append(QString::fromLocal8Bit(::getenv("DISPLAY")));
|
||||
}
|
||||
fprintf(stderr, "\n");
|
||||
#else
|
||||
fprintf(stderr, "KCrash: Application '%s' crashing...\n",
|
||||
s_appName ? s_appName : "<unknown>");
|
||||
#endif
|
||||
|
||||
if (!s_launchDrKonqi) {
|
||||
setCrashHandler(0);
|
||||
raise(sig); // dump core, or whatever is the default action for this signal.
|
||||
QProcess::startDetached(QCoreApplication::applicationFilePath(), args);
|
||||
} else if (s_flags & KCrash::DrKonqi) {
|
||||
const QString drkonqiexe = KStandardDirs::findExe(QString::fromLatin1("drkonqi"));
|
||||
if (drkonqiexe.isEmpty()) {
|
||||
return;
|
||||
}
|
||||
|
||||
const char * argv[27]; // don't forget to update this
|
||||
int i = 0;
|
||||
QStringList args;
|
||||
|
||||
// argument 0 has to be drkonqi
|
||||
argv[i++] = s_drkonqiPath;
|
||||
args.append(QString::fromLatin1("--signal"));
|
||||
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
|
||||
// start up on the correct display
|
||||
argv[i++] = "-display";
|
||||
if ( QX11Info::display() )
|
||||
argv[i++] = XDisplayString(QX11Info::display());
|
||||
else
|
||||
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();
|
||||
const KComponentData kcomponentdata = KGlobal::mainComponent();
|
||||
const KAboutData *kaboutdata = kcomponentdata.isValid() ? kcomponentdata.aboutData() : nullptr;
|
||||
if (kaboutdata) {
|
||||
if (kaboutdata->internalVersion()) {
|
||||
args.append(QString::fromLatin1("--appversion"));
|
||||
args.append(kaboutdata->internalVersion());
|
||||
}
|
||||
|
||||
if (about->internalProgramName()) {
|
||||
argv[i++] = "--programname";
|
||||
argv[i++] = about->internalProgramName();
|
||||
if (kaboutdata->internalProgramName()) {
|
||||
args.append(QString::fromLatin1("--programname"));
|
||||
args.append(kaboutdata->internalProgramName());
|
||||
}
|
||||
|
||||
if (about->internalBugAddress()) {
|
||||
argv[i++] = "--bugaddress";
|
||||
argv[i++] = about->internalBugAddress();
|
||||
if (kaboutdata->internalBugAddress()) {
|
||||
args.append(QString::fromLatin1("--bugaddress"));
|
||||
args.append(kaboutdata->internalBugAddress());
|
||||
}
|
||||
}
|
||||
|
||||
char sidtxt[256];
|
||||
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);
|
||||
QProcess::execute(drkonqiexe, args);
|
||||
}
|
||||
|
||||
if (crashRecursionCounter < 4)
|
||||
{
|
||||
fprintf(stderr, "Unable to start Dr. Konqi\n");
|
||||
}
|
||||
|
||||
_exit(255);
|
||||
::exit(sig);
|
||||
}
|
||||
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
|
|
|
@ -1,23 +1,20 @@
|
|||
/*
|
||||
* This file is part of the KDE Libraries
|
||||
* 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
|
||||
* modify it under the terms of the GNU Library General Public
|
||||
* 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
|
||||
* 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.
|
||||
*
|
||||
*/
|
||||
/* This file is part of the KDE libraries
|
||||
Copyright (C) 2022 Ivailo Monev <xakepa10@gmail.com>
|
||||
|
||||
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 KCRASH_H
|
||||
#define KCRASH_H
|
||||
|
@ -45,110 +42,66 @@
|
|||
*/
|
||||
namespace KCrash
|
||||
{
|
||||
/**
|
||||
* The default crash handler.
|
||||
* Do not call this function directly. Instead, use
|
||||
* setCrashHandler() to set it as your application's crash handler.
|
||||
* @param signal the signal number
|
||||
* @note If you implement your own crash handler, you will have to
|
||||
* call this function from your implementation if you want to use the
|
||||
* features of this namespace.
|
||||
*/
|
||||
KDEUI_EXPORT void defaultCrashHandler (int signal);
|
||||
/**
|
||||
* The default crash handler.
|
||||
* Do not call this function directly. Instead, use
|
||||
* setCrashHandler() to set it as your application's crash handler.
|
||||
* @param signal the signal number
|
||||
* @note If you implement your own crash handler, you will have to
|
||||
* call this function from your implementation if you want to use the
|
||||
* features of this namespace.
|
||||
*/
|
||||
KDEUI_EXPORT void defaultCrashHandler (int signal);
|
||||
|
||||
/**
|
||||
* Typedef for a pointer to a crash handler function.
|
||||
* The function's argument is the number of the signal.
|
||||
*/
|
||||
typedef void (*HandlerType)(int);
|
||||
/**
|
||||
* Typedef for a pointer to a crash handler function.
|
||||
* The function's argument is the number of the signal.
|
||||
*/
|
||||
typedef void (*HandlerType)(int);
|
||||
|
||||
/**
|
||||
* Install a function to be called when a crash occurs.
|
||||
* A crash occurs when one of the following signals is
|
||||
* caught: SIGSEGV, SIGBUS, SIGFPE, SIGILL, SIGABRT.
|
||||
* @param handler this can be one of:
|
||||
* @li null, in which case signal catching is disabled
|
||||
* (by setting the signal handler for the crash signals to SIG_DFL)
|
||||
* @li a user defined function in the form:
|
||||
* static (if in a class) void myCrashHandler(int);
|
||||
* @li if handler is omitted, the default crash handler is installed
|
||||
* @note If you use setDrKonqiEnabled(true), setEmergencySaveFunction(myfunc)
|
||||
* or setFlags(AutoRestart), you do not need to call this function
|
||||
* explicitly. The default crash handler is automatically installed by
|
||||
* those functions if needed. However, if you set a custom crash handler,
|
||||
* those functions will not change it.
|
||||
*/
|
||||
KDEUI_EXPORT void setCrashHandler (HandlerType handler = defaultCrashHandler);
|
||||
/**
|
||||
* Install a function to be called when a crash occurs.
|
||||
* A crash occurs when one of the following signals is
|
||||
* caught: SIGSEGV, SIGBUS, SIGFPE, SIGILL, SIGABRT.
|
||||
* @param handler this can be one of:
|
||||
* @li null, in which case signal catching is disabled
|
||||
* (by setting the signal handler for the crash signals to SIG_DFL)
|
||||
* @li a user defined function in the form:
|
||||
* static (if in a class) void myCrashHandler(int);
|
||||
* @li if handler is omitted, the default crash handler is installed
|
||||
* @note If you use setFlags(AutoRestart), you do not need to call this function
|
||||
* explicitly. The default crash handler is automatically installed by
|
||||
* those functions if needed. However, if you set a custom crash handler,
|
||||
* those functions will not change it.
|
||||
*/
|
||||
KDEUI_EXPORT void setCrashHandler(HandlerType handler = defaultCrashHandler);
|
||||
|
||||
/**
|
||||
* Returns the installed crash handler.
|
||||
* @return the crash handler
|
||||
*/
|
||||
KDEUI_EXPORT HandlerType crashHandler();
|
||||
/**
|
||||
* Returns the installed crash handler.
|
||||
* @return the crash handler
|
||||
*/
|
||||
KDEUI_EXPORT HandlerType crashHandler();
|
||||
|
||||
/**
|
||||
* Installs a function which should try to save the application's data.
|
||||
* @note It is the crash handler's responsibility to call this function.
|
||||
* Therefore, if no crash handler is set, the default crash handler
|
||||
* is installed to ensure the save function will be called.
|
||||
* @param saveFunction the handler to install
|
||||
*/
|
||||
KDEUI_EXPORT void setEmergencySaveFunction (HandlerType saveFunction = 0);
|
||||
/**
|
||||
* Options to determine how the default crash handler should behave.
|
||||
*/
|
||||
enum CrashFlag {
|
||||
AutoRestart = 1, ///< autorestart this application. Only sensible for KUniqueApplications. @since 4.1.
|
||||
DrKonqi = 2 ///< launchers DrKonqi. @since 4.23.
|
||||
};
|
||||
Q_DECLARE_FLAGS(CrashFlags, CrashFlag)
|
||||
|
||||
/**
|
||||
* Returns the currently set emergency save function.
|
||||
* @return the emergency save function
|
||||
*/
|
||||
KDEUI_EXPORT HandlerType emergencySaveFunction();
|
||||
/**
|
||||
* Set options to determine how the default crash handler should behave.
|
||||
* @param flags ORed together CrashFlags
|
||||
*/
|
||||
KDEUI_EXPORT void setFlags(CrashFlags flags);
|
||||
|
||||
/**
|
||||
* Options to determine how the default crash handler should behave.
|
||||
*/
|
||||
enum CrashFlag {
|
||||
KeepFDs = 1, ///< don't close all file descriptors immediately
|
||||
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();
|
||||
/**
|
||||
* Get currently set options that determine how the default crash handler should behave.
|
||||
* @param flags ORed together CrashFlags
|
||||
*/
|
||||
KDEUI_EXPORT CrashFlags flags();
|
||||
}
|
||||
|
||||
Q_DECLARE_OPERATORS_FOR_FLAGS(KCrash::CrashFlags)
|
||||
|
|
|
@ -1,45 +1,10 @@
|
|||
project(kdeinit)
|
||||
project(kinit)
|
||||
|
||||
if(ENABLE_TESTING)
|
||||
add_subdirectory(tests)
|
||||
endif()
|
||||
|
||||
include_directories(${KDE4_KPARTS_INCLUDES})
|
||||
|
||||
########### 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})
|
||||
add_definitions(-DKDE_DEFAULT_DEBUG_AREA=1210)
|
||||
|
||||
########### kioslave ###############
|
||||
|
||||
|
@ -49,14 +14,11 @@ target_link_libraries(kioslave ${QT_QTCORE_LIBRARY})
|
|||
|
||||
install(TARGETS kioslave DESTINATION ${KDE4_LIBEXEC_INSTALL_DIR})
|
||||
|
||||
|
||||
########### klauncher ###############
|
||||
|
||||
set(klauncher_SRCS
|
||||
klauncher.cpp
|
||||
klauncher_main.cpp
|
||||
klauncher_adaptor.cpp
|
||||
autostart.cpp
|
||||
klauncher_cmds.cpp
|
||||
# just so that it gets generated
|
||||
${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.
|
||||
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 ###############
|
||||
|
||||
|
@ -77,10 +44,3 @@ install(
|
|||
${CMAKE_CURRENT_BINARY_DIR}/org.kde.KLauncher.xml
|
||||
DESTINATION ${KDE4_DBUS_INTERFACES_INSTALL_DIR}
|
||||
)
|
||||
|
||||
########### config-kdeinit.h ############
|
||||
|
||||
configure_file(
|
||||
config-kdeinit.h.cmake
|
||||
${CMAKE_CURRENT_BINARY_DIR}/config-kdeinit.h
|
||||
)
|
||||
|
|
|
@ -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();
|
||||
}
|
|
@ -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
|
|
@ -1,5 +0,0 @@
|
|||
|
||||
/* These are for proctitle.cpp: */
|
||||
#cmakedefine HAVE___PROGNAME 1
|
||||
#cmakedefine HAVE___PROGNAME_FULL 1
|
||||
#cmakedefine HAVE_SETPROCTITLE 1
|
1533
kinit/kinit.cpp
1533
kinit/kinit.cpp
File diff suppressed because it is too large
Load diff
1254
kinit/klauncher.cpp
1254
kinit/klauncher.cpp
File diff suppressed because it is too large
Load diff
|
@ -1,251 +1,39 @@
|
|||
/*
|
||||
This file is part of the KDE libraries
|
||||
Copyright (c) 1999 Waldo Bastian <bastian@kde.org>
|
||||
/* This file is part of the KDE libraries
|
||||
Copyright (C) 2022 Ivailo Monev <xakepa10@gmail.com>
|
||||
|
||||
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 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.
|
||||
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.
|
||||
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_H_
|
||||
#define _KLAUNCHER_H_
|
||||
#ifndef KLAUNCHER_H
|
||||
#define KLAUNCHER_H
|
||||
|
||||
#include "autostart.h"
|
||||
#include "klauncher_adaptor.h"
|
||||
|
||||
#include <sys/types.h>
|
||||
#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;
|
||||
};
|
||||
#include <QObject>
|
||||
|
||||
class KLauncher : public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
Q_OBJECT
|
||||
public:
|
||||
KLauncher(int kdeinitSocket);
|
||||
KLauncher(QObject *parent = nullptr);
|
||||
~KLauncher();
|
||||
|
||||
~KLauncher();
|
||||
void setSessionManager(const QByteArray &sessionmanager);
|
||||
|
||||
void close();
|
||||
|
||||
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);
|
||||
private:
|
||||
KLauncherAdaptor* m_adaptor;
|
||||
};
|
||||
#endif
|
||||
|
||||
#endif // KLAUNCHER_H
|
||||
|
|
|
@ -1,141 +1,351 @@
|
|||
/*
|
||||
* Copyright 2006, 2007 Thiago Macieira <thiago@kde.org>
|
||||
* 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/>.
|
||||
*
|
||||
*/
|
||||
/* This file is part of the KDE libraries
|
||||
Copyright (C) 2022 Ivailo Monev <xakepa10@gmail.com>
|
||||
|
||||
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 "klauncher_adaptor.h"
|
||||
#include "klauncher.h"
|
||||
#include "kprotocolmanager.h"
|
||||
#include "krun.h"
|
||||
#include "kstandarddirs.h"
|
||||
#include "kautostart.h"
|
||||
#include "kdebug.h"
|
||||
|
||||
/*
|
||||
* Implementation of adaptor class KLauncherAdaptor
|
||||
*
|
||||
* This file was initially generated by dbusidl2cpp version 0.4,
|
||||
* but then modified by hand.
|
||||
*/
|
||||
#include <QDir>
|
||||
#include <QApplication>
|
||||
#include <QThread>
|
||||
#include <QElapsedTimer>
|
||||
#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)
|
||||
: QDBusAbstractAdaptor(parent)
|
||||
: QDBusAbstractAdaptor(parent)
|
||||
{
|
||||
// constructor
|
||||
setAutoRelaySignals(true);
|
||||
m_environment = QProcessEnvironment::systemEnvironment();
|
||||
}
|
||||
|
||||
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)
|
||||
{
|
||||
// handle method call org.kde.KLauncher.autoStart
|
||||
static_cast<KLauncher *>(parent())->autoStart(phase);
|
||||
if (m_autostart.isEmpty()) {
|
||||
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)
|
||||
{
|
||||
// handle method call org.kde.KLauncher.exec_blind
|
||||
static_cast<KLauncher *>(parent())->exec_blind(name, arg_list);
|
||||
const QString appexe = findExe(name);
|
||||
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
|
||||
static_cast<KLauncher *>(parent())->kdeinit_exec(app, args, QString(), env, startup_id, false, msg);
|
||||
return 0; // delayed reply
|
||||
return kdeinit_exec_with_workdir(app, args, QDir::currentPath(), env, startup_id, msg, dbusServiceName, error, pid);
|
||||
}
|
||||
|
||||
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
|
||||
static_cast<KLauncher *>(parent())->kdeinit_exec(app, args, QString(), env, startup_id, true, msg);
|
||||
return 0; // delayed reply
|
||||
const int result = kdeinit_exec(app, args, env, startup_id, msg, dbusServiceName, error, pid);
|
||||
if (result != KLauncherAdaptor::NoError) {
|
||||
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
|
||||
static_cast<KLauncher *>(parent())->kdeinit_exec(app, args, workdir, env, startup_id, false, msg);
|
||||
return 0; // delayed reply
|
||||
const QString appexe = findExe(app);
|
||||
if (appexe.isEmpty()) {
|
||||
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()
|
||||
{
|
||||
// handle method call org.kde.KLauncher.reparseConfiguration
|
||||
static_cast<KLauncher *>(parent())->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);
|
||||
kDebug() << "reparsing configuration";
|
||||
KProtocolManager::reparseConfiguration();
|
||||
}
|
||||
|
||||
void KLauncherAdaptor::setLaunchEnv(const QString &name, const QString &value)
|
||||
{
|
||||
// handle method call org.kde.KLauncher.setLaunchEnv
|
||||
static_cast<KLauncher *>(parent())->setLaunchEnv(name, value);
|
||||
kDebug() << "setting environment variable" << name << "to" << 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
|
||||
KLauncher *p = static_cast<KLauncher *>(parent());
|
||||
p->start_service_by_desktop_name(serviceName, urls, envs, startup_id, blind, msg);
|
||||
dbusServiceName = p->requestResult.dbusName;
|
||||
error = p->requestResult.error;
|
||||
pid = p->requestResult.pid;
|
||||
return p->requestResult.result;
|
||||
KService::Ptr kservice = KService::serviceByDesktopName(serviceName);
|
||||
if (!kservice) {
|
||||
error = i18n("Invalid service name: %1", serviceName);
|
||||
return KLauncherAdaptor::ServiceError;
|
||||
}
|
||||
return start_service_by_desktop_path(kservice->entryPath(), urls, envs, startup_id, blind, msg, dbusServiceName, error, 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)
|
||||
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
|
||||
KLauncher *p = static_cast<KLauncher *>(parent());
|
||||
p->start_service_by_desktop_path(serviceName, urls, envs, startup_id, blind, msg);
|
||||
dbusServiceName = p->requestResult.dbusName;
|
||||
error = p->requestResult.error;
|
||||
pid = p->requestResult.pid;
|
||||
return p->requestResult.result;
|
||||
KService::Ptr kservice = KService::serviceByStorageId(serviceName);
|
||||
if (!kservice) {
|
||||
error = i18n("Invalid service path: %1", serviceName);
|
||||
return KLauncherAdaptor::ServiceError;
|
||||
}
|
||||
if (urls.size() > 1 && !kservice->allowMultipleFiles()) {
|
||||
// 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
|
||||
static_cast<KLauncher *>(parent())->waitForSlave(pid, msg);
|
||||
QProcess* process = qobject_cast<QProcess*>(sender());
|
||||
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());
|
||||
p->terminate_kdeinit();
|
||||
QProcess* process = qobject_cast<QProcess*>(sender());
|
||||
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"
|
||||
|
|
|
@ -1,47 +1,47 @@
|
|||
/*
|
||||
* Copyright 2006, 2007 Thiago Macieira <thiago@kde.org>
|
||||
* 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/>.
|
||||
*
|
||||
*/
|
||||
/* This file is part of the KDE libraries
|
||||
Copyright (C) 2022 Ivailo Monev <xakepa10@gmail.com>
|
||||
|
||||
#ifndef KLAUNCHER_ADAPTOR_H_18181148166088
|
||||
#define KLAUNCHER_ADAPTOR_H_18181148166088
|
||||
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.
|
||||
|
||||
#include <QtCore/QObject>
|
||||
#include <QtDBus/QDBusAbstractAdaptor>
|
||||
#include <QtDBus/QDBusMessage>
|
||||
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.
|
||||
|
||||
#include <QList>
|
||||
#include <QMap>
|
||||
#include <QString>
|
||||
#include <QStringList>
|
||||
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.
|
||||
*/
|
||||
|
||||
/*
|
||||
* Adaptor class for interface org.kde.KLauncher
|
||||
*/
|
||||
#ifndef KLAUNCHER_ADAPTOR_H
|
||||
#define KLAUNCHER_ADAPTOR_H
|
||||
|
||||
#include "kstartupinfo.h"
|
||||
|
||||
#include <QDBusAbstractAdaptor>
|
||||
#include <QDBusMessage>
|
||||
#include <QProcess>
|
||||
|
||||
// Adaptor class for interface org.kde.KLauncher
|
||||
class KLauncherAdaptor: public QDBusAbstractAdaptor
|
||||
{
|
||||
Q_OBJECT
|
||||
Q_CLASSINFO("D-Bus Interface", "org.kde.KLauncher")
|
||||
public:
|
||||
enum KLauncherError {
|
||||
NoError = 0,
|
||||
ServiceError = 1,
|
||||
FindError = 2,
|
||||
ArgumentsError = 3,
|
||||
ExecError = 4,
|
||||
DBusError = 5
|
||||
};
|
||||
|
||||
KLauncherAdaptor(QObject *parent);
|
||||
virtual ~KLauncherAdaptor();
|
||||
~KLauncherAdaptor();
|
||||
|
||||
public: // PROPERTIES
|
||||
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_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();
|
||||
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);
|
||||
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);
|
||||
void waitForSlave(qint64 pid, const QDBusMessage &msg);
|
||||
void terminate_kdeinit();
|
||||
|
||||
Q_SIGNALS: // SIGNALS
|
||||
void autoStart0Done();
|
||||
void autoStart1Done();
|
||||
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
|
||||
|
|
|
@ -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";
|
||||
}
|
||||
}
|
|
@ -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
|
|
@ -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();
|
||||
}
|
3
kinit/org.kde.klauncher.service.in
Normal file
3
kinit/org.kde.klauncher.service.in
Normal file
|
@ -0,0 +1,3 @@
|
|||
[D-BUS Service]
|
||||
Name=org.kde.klauncher
|
||||
Exec=@KDE4_BIN_INSTALL_DIR@/klauncher4
|
|
@ -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);
|
||||
}
|
|
@ -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 */
|
|
@ -38,7 +38,6 @@
|
|||
#include <kglobal.h>
|
||||
#include <kstandarddirs.h>
|
||||
#include <ktoolinvocation.h>
|
||||
#include <klauncher_iface.h>
|
||||
|
||||
#include "kservice.h"
|
||||
#include <kio/global.h>
|
||||
|
@ -300,10 +299,6 @@ void Slave::hold(const KUrl &url)
|
|||
emit slaveDied(this);
|
||||
}
|
||||
deref();
|
||||
// Call KLauncher::waitForSlave(pid);
|
||||
{
|
||||
KToolInvocation::klauncher()->waitForSlave(d->m_pid);
|
||||
}
|
||||
}
|
||||
|
||||
void Slave::suspend()
|
||||
|
@ -402,95 +397,41 @@ Slave* Slave::createSlave( const QString &protocol, const KUrl& url, int& error,
|
|||
Slave *slave = new Slave(protocol);
|
||||
QString slaveAddress = slave->d_func()->slaveconnserver->address();
|
||||
|
||||
#ifdef Q_OS_UNIX
|
||||
// In such case we start the slave via QProcess.
|
||||
// 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)
|
||||
QString _name = KProtocolInfo::exec(protocol);
|
||||
if (_name.isEmpty())
|
||||
{
|
||||
// check the UID of klauncher
|
||||
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_text = i18n("Unknown protocol '%1'.", protocol);
|
||||
error = KIO::ERR_CANNOT_LAUNCH_PROCESS;
|
||||
delete slave;
|
||||
return 0;
|
||||
}
|
||||
pid_t pid = reply;
|
||||
if (!pid)
|
||||
KPluginLoader lib(_name, KGlobal::mainComponent());
|
||||
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;
|
||||
delete slave;
|
||||
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;
|
||||
}
|
||||
|
||||
Slave* Slave::holdSlave( const QString &protocol, const KUrl& url )
|
||||
{
|
||||
//kDebug(7002) << "holdSlave" << protocol << "for" << url;
|
||||
Slave *slave = new Slave(protocol);
|
||||
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;
|
||||
return 0;
|
||||
}
|
||||
|
||||
bool Slave::checkForHeldSlave(const KUrl &url)
|
||||
{
|
||||
return KToolInvocation::klauncher()->checkForHeldSlave(url.url());
|
||||
return false;
|
||||
}
|
||||
|
||||
#include "moc_slave.cpp"
|
||||
|
|
|
@ -155,9 +155,9 @@ void KRunUnitTest::testProcessDesktopExecNoFile_data()
|
|||
KUrl::List l4; l4 << KUrl( "http://login:password@www.kde.org" );
|
||||
|
||||
// A real-world use case would be kate.
|
||||
// But I picked kdeinit4 since it's installed by kdelibs
|
||||
QString kdeinit = KStandardDirs::findExe("kdeinit4");
|
||||
if (kdeinit.isEmpty()) kdeinit = "kdeinit4";
|
||||
// But I picked klauncher4 since it's installed by kdelibs
|
||||
QString klauncher = KStandardDirs::findExe("klauncher4");
|
||||
if (klauncher.isEmpty()) klauncher = "klauncher4";
|
||||
|
||||
QString kioexec = KStandardDirs::findExe("kioexec");
|
||||
if (kioexec.isEmpty())
|
||||
|
@ -165,30 +165,30 @@ void KRunUnitTest::testProcessDesktopExecNoFile_data()
|
|||
|
||||
QString kmailservice = KStandardDirs::findExe("kmailservice");
|
||||
if (kmailservice.isEmpty()) kmailservice = "kmailservice";
|
||||
if (!kdeinit.isEmpty()) {
|
||||
if (!klauncher.isEmpty()) {
|
||||
QVERIFY(!kmailservice.isEmpty());
|
||||
}
|
||||
|
||||
// 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 l1") << "kdeinit4 %U" << l1 << false << QString(kdeinit + " /tmp");
|
||||
QTest::newRow("%U l2") << "kdeinit4 %U" << l2 << false << QString(kdeinit + " http://localhost/foo");
|
||||
QTest::newRow("%U l3") << "kdeinit4 %U" << l3 << false << QString(kdeinit + " /local/file http://remotehost.org/bar");
|
||||
QTest::newRow("%U l0") << "klauncher4 %U" << l0 << false << klauncher;
|
||||
QTest::newRow("%U l1") << "klauncher4 %U" << l1 << false << QString(klauncher + " /tmp");
|
||||
QTest::newRow("%U l2") << "klauncher4 %U" << l2 << false << QString(klauncher + " http://localhost/foo");
|
||||
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 l1") << "kdeinit4 %u" << l1 << false << QString(kdeinit + " /tmp");
|
||||
QTest::newRow("%u l2") << "kdeinit4 %u" << l2 << false << QString(kdeinit + " http://localhost/foo");
|
||||
//QTest::newRow("%u l3") << "kdeinit4 %u" << l3 << false << kdeinit; // gives runtime warning
|
||||
//QTest::newRow("%u l0") << "klauncher4 %u" << l0 << false << klauncher; // gives runtime warning
|
||||
QTest::newRow("%u l1") << "klauncher4 %u" << l1 << false << QString(klauncher + " /tmp");
|
||||
QTest::newRow("%u l2") << "klauncher4 %u" << l2 << false << QString(klauncher + " http://localhost/foo");
|
||||
//QTest::newRow("%u l3") << "klauncher4 %u" << l3 << false << klauncher; // gives runtime warning
|
||||
|
||||
QTest::newRow("%F l0") << "kdeinit4 %F" << l0 << false << kdeinit;
|
||||
QTest::newRow("%F l1") << "kdeinit4 %F" << l1 << false << QString(kdeinit + " /tmp");
|
||||
QTest::newRow("%F l2") << "kdeinit4 %F" << l2 << false << QString(kioexec + " 'kdeinit4 %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 l0") << "klauncher4 %F" << l0 << false << klauncher;
|
||||
QTest::newRow("%F l1") << "klauncher4 %F" << l1 << false << QString(klauncher + " /tmp");
|
||||
QTest::newRow("%F l2") << "klauncher4 %F" << l2 << false << QString(kioexec + " 'klauncher4 %F' http://localhost/foo");
|
||||
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\"'\\\"'"
|
||||
<< l1 << false << QString(m_sh + " -c 'kdeinit4 \\\"/tmp\\\"'");
|
||||
QTest::newRow("sh -c klauncher4 %F") << "sh -c \"klauncher4 \"'\\\"'\"%F\"'\\\"'"
|
||||
<< l1 << false << QString(m_sh + " -c 'klauncher4 \\\"/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");
|
||||
|
|
Loading…
Add table
Reference in a new issue