diff --git a/ConfigureChecks.cmake b/ConfigureChecks.cmake index 31e93f63..09eaad15 100644 --- a/ConfigureChecks.cmake +++ b/ConfigureChecks.cmake @@ -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) diff --git a/kdecore/kdebug.areas b/kdecore/kdebug.areas index 0187bbd6..13e0c57d 100644 --- a/kdecore/kdebug.areas +++ b/kdecore/kdebug.areas @@ -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 diff --git a/kdecore/kernel/ktoolinvocation.cpp b/kdecore/kernel/ktoolinvocation.cpp index 87340b6d..f8213b30 100644 --- a/kdecore/kernel/ktoolinvocation.cpp +++ b/kdecore/kernel/ktoolinvocation.cpp @@ -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; } diff --git a/kdecore/tests/kstandarddirstest.cpp b/kdecore/tests/kstandarddirstest.cpp index 3b650621..fd754c5e 100644 --- a/kdecore/tests/kstandarddirstest.cpp +++ b/kdecore/tests/kstandarddirstest.cpp @@ -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(); diff --git a/kdecore/util/klauncher_iface.h b/kdecore/util/klauncher_iface.h index 5060f35e..94897dfd 100644 --- a/kdecore/util/klauncher_iface.h +++ b/kdecore/util/klauncher_iface.h @@ -100,24 +100,6 @@ public Q_SLOTS: // METHODS return callWithArgumentList(QDBus::Block, QLatin1String("reparseConfiguration"), argumentList); } - inline QDBusReply requestHoldSlave(const QString &url, const QString &app_socket) - { - QList argumentList; - argumentList << qVariantFromValue(url) << qVariantFromValue(app_socket); - return callWithArgumentList(QDBus::Block, QLatin1String("requestHoldSlave"), argumentList); - } - - inline QDBusReply requestSlave(const QString &protocol, const QString &host, const QString &app_socket, QString &error) - { - QList 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(reply.arguments().at(1)); - } - return reply; - } - inline QDBusReply setLaunchEnv(const QString &name, const QString &value) { QList argumentList; @@ -151,20 +133,6 @@ public Q_SLOTS: // METHODS return reply; } - inline QDBusReply waitForSlave(int pid) - { - QList argumentList; - argumentList << qVariantFromValue(pid); - return callWithArgumentList(QDBus::Block, QLatin1String("waitForSlave"), argumentList); - } - - inline QDBusReply checkForHeldSlave(const QString &url) - { - QList argumentList; - argumentList << qVariantFromValue(url); - return callWithArgumentList(QDBus::Block, QLatin1String("checkForHeldSlave"), argumentList); - } - Q_SIGNALS: // SIGNALS void autoStart0Done(); void autoStart1Done(); diff --git a/kded/kbuildsycoca.cpp b/kded/kbuildsycoca.cpp index 16295ac1..88908b82 100644 --- a/kded/kbuildsycoca.cpp +++ b/kded/kbuildsycoca.cpp @@ -51,12 +51,14 @@ #include #include #ifndef KBUILDSYCOCA_NO_KCRASH +#include #include #endif #include #include #include +#include typedef QHash KBSEntryDict; typedef QList 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 diff --git a/kdeui/kernel/kapplication.cpp b/kdeui/kernel/kapplication.cpp index eb30e674..68de5b74 100644 --- a/kdeui/kernel/kapplication.cpp +++ b/kdeui/kernel/kapplication.cpp @@ -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 diff --git a/kdeui/kernel/kapplication.h b/kdeui/kernel/kapplication.h index d6d5bd9b..8236e180 100644 --- a/kdeui/kernel/kapplication.h +++ b/kdeui/kernel/kapplication.h @@ -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, diff --git a/kdeui/util/kcrash.cpp b/kdeui/util/kcrash.cpp index 9fd9f9eb..97079be0 100644 --- a/kdeui/util/kcrash.cpp +++ b/kdeui/util/kcrash.cpp @@ -1,710 +1,157 @@ -/* - * This file is part of the KDE Libraries - * Copyright (C) 2000 Timo Hummel - * Tom Braun - * Copyright 2009 KDE e.V. - * By Adriaan de Groot - * Copyright (C) 2010 George Kiagiadakis - * - * 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 + + 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 -#include -#include +#include "kcmdlineargs.h" +#include "kde_file.h" +#include "kaboutdata.h" +#include "kcomponentdata.h" +#include "kstandarddirs.h" +#include "kdebug.h" -#include +#include +#include +#include -#include #include -#include -#include -#include - -#include -#include -#include -#include -#include -#include -#ifdef Q_OS_LINUX -#include -#endif -#include - -#include -#include -#include -#include -#include -#include -#include - -#include <../kinit/klauncher_cmds.h> - -#include -#include - -#if defined Q_WS_X11 -#include #include -#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 -#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(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 : "" , - s_appPath ? s_appPath : "", 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 : ""); -#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 : ""; - - 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); -} - -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; -} - diff --git a/kdeui/util/kcrash.h b/kdeui/util/kcrash.h index 7475d132..026cd78c 100644 --- a/kdeui/util/kcrash.h +++ b/kdeui/util/kcrash.h @@ -1,23 +1,20 @@ -/* - * This file is part of the KDE Libraries - * Copyright (C) 2000 Timo Hummel - * Tom Braun - * 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 + + 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) diff --git a/kinit/CMakeLists.txt b/kinit/CMakeLists.txt index 9913d7b5..6d637d47 100644 --- a/kinit/CMakeLists.txt +++ b/kinit/CMakeLists.txt @@ -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 -) diff --git a/kinit/autostart.cpp b/kinit/autostart.cpp deleted file mode 100644 index b9d05244..00000000 --- a/kinit/autostart.cpp +++ /dev/null @@ -1,122 +0,0 @@ -/* - * This file is part of the KDE libraries - * Copyright (c) 2001 Waldo Bastian - * - * 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 -#include -#include - -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 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(); -} diff --git a/kinit/autostart.h b/kinit/autostart.h deleted file mode 100644 index 0dad82d6..00000000 --- a/kinit/autostart.h +++ /dev/null @@ -1,48 +0,0 @@ -/* - This file is part of the KDE libraries - Copyright (c) 2001 Waldo Bastian - - 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 - -class AutoStartItem; -typedef QList 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 diff --git a/kinit/config-kdeinit.h.cmake b/kinit/config-kdeinit.h.cmake deleted file mode 100644 index 5a62c203..00000000 --- a/kinit/config-kdeinit.h.cmake +++ /dev/null @@ -1,5 +0,0 @@ - -/* These are for proctitle.cpp: */ -#cmakedefine HAVE___PROGNAME 1 -#cmakedefine HAVE___PROGNAME_FULL 1 -#cmakedefine HAVE_SETPROCTITLE 1 diff --git a/kinit/kinit.cpp b/kinit/kinit.cpp deleted file mode 100644 index 19a35be1..00000000 --- a/kinit/kinit.cpp +++ /dev/null @@ -1,1533 +0,0 @@ -/* - * This file is part of the KDE libraries - * Copyright (c) 1999-2000 Waldo Bastian - * (c) 1999 Mario Weilguni - * (c) 2001 Lubos Lunak - * - * 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 -#include - -#include -#include -#include -#include -#include -#include -#include -#include // Needed on some systems. -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include "klauncher_cmds.h" -#include "proctitle.h" - -#ifdef Q_OS_LINUX -#include -#ifndef PR_SET_NAME -#define PR_SET_NAME 15 -#endif -#endif - -#ifdef Q_WS_X11 -#include -#include -#include -#include -#endif - -// #define SKIP_PROCTITLE 1 - -extern char **environ; - -#ifdef Q_WS_X11 -static int X11fd = -1; -static Display *X11display = 0; -static int X11_startup_notify_fd = -1; -static Display *X11_startup_notify_display = 0; -#endif -static KComponentData *s_instance = 0; -#define MAX_SOCK_FILE 255 -static char sock_file[MAX_SOCK_FILE]; - -#ifdef Q_WS_X11 -#define DISPLAY "DISPLAY" -#elif defined(Q_WS_QWS) -#define DISPLAY "QWS_DISPLAY" -#else -#error Use QT/X11 or QT/Embedded -#endif - -/* Group data */ -static struct { - int maxname; - int fd[2]; - int launcher[2]; /* socket pair for launcher communication */ - int deadpipe[2]; /* pipe used to detect dead children */ - int initpipe[2]; - int wrapper; /* socket for wrapper communication */ - int accepted_fd; /* socket accepted and that must be closed in the child process */ - char result; - int exit_status; - pid_t fork; - pid_t launcher_pid; - int n; - char **argv; - int (*func)(int, char *[]); - int (*launcher_func)(int); - bool debug_wait; - QByteArray errorMsg; - bool launcher_ok; - bool suicide; -} d; - -struct child -{ - pid_t pid; - int sock; /* fd to write message when child is dead*/ - struct child *next; -}; - -static struct child *children; - -#ifdef Q_WS_X11 -extern "C" { -int kdeinit_xio_errhandler( Display * ); -int kdeinit_x_errhandler( Display *, XErrorEvent *err ); -} -#endif - -/* - * Clean up the file descriptor table by closing all file descriptors - * that are still open. - * - * This function is called very early in the main() function, so that - * we don't leak anything that was leaked to us. - */ -static void cleanup_fds() -{ - int maxfd = FD_SETSIZE; - struct rlimit rl; - if (getrlimit(RLIMIT_NOFILE, &rl) == 0) - maxfd = rl.rlim_max; - for (int fd = 3; fd < maxfd; ++fd) - { - close(fd); - } -} - -/* - * Close fd's which are only useful for the parent process. - * Restore default signal handlers. - */ -static void close_fds() -{ - while (struct child *child = children) { - close(child->sock); - children = child->next; - free(child); - } - - if (d.deadpipe[0] != -1) - { - close(d.deadpipe[0]); - d.deadpipe[0] = -1; - } - - if (d.deadpipe[1] != -1) - { - close(d.deadpipe[1]); - d.deadpipe[1] = -1; - } - - if (d.initpipe[0] != -1) - { - close(d.initpipe[0]); - d.initpipe[0] = -1; - } - - if (d.initpipe[1] != -1) - { - close(d.initpipe[1]); - d.initpipe[1] = -1; - } - - if (d.launcher[0] != -1) - { - close(d.launcher[0]); - d.launcher[0] = -1; - } - if (d.wrapper != -1) - { - close(d.wrapper); - d.wrapper = -1; - } - if (d.accepted_fd != -1) - { - close(d.accepted_fd); - d.accepted_fd = -1; - } -#ifdef Q_WS_X11 - if (X11fd >= 0) - { - close(X11fd); - X11fd = -1; - } - if (X11_startup_notify_fd >= 0 && X11_startup_notify_fd != X11fd ) - { - close(X11_startup_notify_fd); - X11_startup_notify_fd = -1; - } -#endif - - KDE_signal(SIGCHLD, SIG_DFL); - KDE_signal(SIGPIPE, SIG_DFL); -} - -/* Notify wrapper program that the child it started has finished. */ -static void child_died(pid_t exit_pid, int exit_status) -{ - struct child *child, **childptr = &children; - - while ((child = *childptr)) - { - if (child->pid == exit_pid) - { - /* Send a message with the return value of the child on the control socket */ - klauncher_header request_header; - long request_data[2]; - request_header.cmd = LAUNCHER_CHILD_DIED; - request_header.arg_length = sizeof(long) * 2; - request_data[0] = exit_pid; - request_data[1] = exit_status; - write(child->sock, &request_header, sizeof(request_header)); - write(child->sock, request_data, request_header.arg_length); - close(child->sock); - - *childptr = child->next; - free(child); - return; - } - - childptr = &child->next; - } -} - - -static void exitWithErrorMsg(const QString &errorMsg) -{ - fprintf( stderr, "%s\n", errorMsg.toLocal8Bit().data() ); - QByteArray utf8ErrorMsg = errorMsg.toUtf8(); - d.result = 3; // Error with msg - write(d.fd[1], &d.result, 1); - int l = utf8ErrorMsg.length(); - write(d.fd[1], &l, sizeof(int)); - write(d.fd[1], utf8ErrorMsg.data(), l); - close(d.fd[1]); - exit(255); -} - -static void setup_tty( const char* tty ) -{ - if( tty == NULL || *tty == '\0' ) - return; - int fd = KDE_open( tty, O_WRONLY ); - if( fd < 0 ) - { - perror( "kdeinit4: could not open() tty" ); - return; - } - if( dup2( fd, STDOUT_FILENO ) < 0 ) - { - perror( "kdeinit4: could not dup2() stdout tty" ); - } - if( dup2( fd, STDERR_FILENO ) < 0 ) - { - perror( "kdeinit4: could not dup2() stderr tty" ); - } - close( fd ); -} - -// from kdecore/netwm.cpp -static int get_current_desktop( Display* disp ) -{ - int desktop = 0; // no desktop by default -#ifdef Q_WS_X11 // Only X11 supports multiple desktops - Atom net_current_desktop = XInternAtom( disp, "_NET_CURRENT_DESKTOP", False ); - Atom type_ret; - int format_ret; - unsigned char *data_ret; - unsigned long nitems_ret, unused; - if( XGetWindowProperty( disp, DefaultRootWindow( disp ), net_current_desktop, - 0l, 1l, False, XA_CARDINAL, &type_ret, &format_ret, &nitems_ret, &unused, &data_ret ) - == Success) - { - if (type_ret == XA_CARDINAL && format_ret == 32 && nitems_ret == 1) - desktop = *((long *) data_ret) + 1; - if (data_ret) - XFree ((char*) data_ret); - } -#endif - return desktop; -} - -// var has to be e.g. "DISPLAY=", i.e. with = -const char* get_env_var( const char* var, int envc, const char* envs ) -{ - if( envc > 0 ) - { // get the var from envs - const char* env_l = envs; - int ln = strlen( var ); - for (int i = 0; i < envc; i++) - { - if( strncmp( env_l, var, ln ) == 0 ) - return env_l + ln; - while(*env_l != 0) env_l++; - env_l++; - } - } - return NULL; -} - -#ifdef Q_WS_X11 -static void init_startup_info( KStartupInfoId& id, const char* bin, - int envc, const char* envs ) -{ - const char* dpy = get_env_var( DISPLAY"=", envc, envs ); - // this may be called in a child, so it can't use display open using X11display - // also needed for multihead - X11_startup_notify_display = XOpenDisplay( dpy ); - if( X11_startup_notify_display == NULL ) - return; - X11_startup_notify_fd = XConnectionNumber( X11_startup_notify_display ); - KStartupInfoData data; - int desktop = get_current_desktop( X11_startup_notify_display ); - data.setDesktop( desktop ); - data.setBin(QFile::decodeName(bin)); - KStartupInfo::sendChangeX( X11_startup_notify_display, id, data ); - XFlush( X11_startup_notify_display ); -} - -static void complete_startup_info( KStartupInfoId& id, pid_t pid ) -{ - if( X11_startup_notify_display == NULL ) - return; - if( pid == 0 ) // failure - KStartupInfo::sendFinishX( X11_startup_notify_display, id ); - else - { - KStartupInfoData data; - data.addPid( pid ); - data.setHostname(); - KStartupInfo::sendChangeX( X11_startup_notify_display, id, data ); - } - XCloseDisplay( X11_startup_notify_display ); - X11_startup_notify_display = NULL; - X11_startup_notify_fd = -1; -} -#endif - -static QByteArray execpath_avoid_loops( const QByteArray& exec, int envc, const char* envs, bool avoid_loops ) -{ - QStringList paths; - static const QChar pathSep = QChar::fromLatin1(':'); - if( envc > 0 ) /* use the passed environment */ - { - const char* path = get_env_var( "PATH=", envc, envs ); - if( path != NULL ) - paths = QFile::decodeName(path).split(pathSep); - } else { - paths = QString::fromLocal8Bit(qgetenv("PATH")).split(pathSep, QString::KeepEmptyParts); - } - QString execpath = s_instance->dirs()->findExe(QFile::decodeName(exec), paths.join(pathSep)); - if (avoid_loops && !execpath.isEmpty()) { - const int pos = execpath.lastIndexOf(QLatin1Char('/')); - const QString bin_path = execpath.left(pos); - for( QStringList::Iterator it = paths.begin(); - it != paths.end(); - ++it ) { - if( *it == bin_path || *it == bin_path + QLatin1Char('/')) { - paths.erase( it ); - break; // --> - } - } - execpath = s_instance->dirs()->findExe(QFile::decodeName(exec), paths.join(pathSep)); - } - return QFile::encodeName(execpath); -} - -static pid_t launch(int argc, const char *_name, const char *args, - const char *cwd=0, int envc=0, const char *envs=0, - const char *tty=0, bool avoid_loops = false, - const char* startup_id_str = "0" ) // krazy:exclude=doublequote_chars -{ - QString lib; - QByteArray name; - QByteArray exec; - QString libpath; - QByteArray execpath; - - if (_name[0] != '/') { - name = _name; - lib = QFile::decodeName(name); - exec = name; - KPluginLoader klib(lib, *s_instance ); - libpath = klib.fileName(); - execpath = execpath_avoid_loops(exec, envc, envs, avoid_loops); - } else { - name = _name; - lib = QFile::decodeName(name); - name = name.mid(name.lastIndexOf('/') + 1); - exec = _name; - if (lib.endsWith(QLatin1String(".so"))) - libpath = lib; - else { - execpath = exec; - } - } -#ifndef NDEBUG - fprintf(stderr,"kdeinit4: preparing to launch %s\n", libpath.isEmpty() - ? execpath.constData() : libpath.toUtf8().constData()); -#endif - if (!args) { - argc = 1; - } - - if (0 > pipe(d.fd)) - { - perror("kdeinit4: pipe() failed"); - d.result = 3; - d.errorMsg = i18n("Unable to start new process.\n" - "The system may have reached the maximum number of open files possible or the maximum number of open files that you are allowed to use has been reached.").toUtf8(); - d.fork = 0; - return d.fork; - } - -#ifdef Q_WS_X11 - KStartupInfoId startup_id; - startup_id.initId( startup_id_str ); - if( !startup_id.none()) - init_startup_info( startup_id, name, envc, envs ); -#endif - // find out this path before forking, doing it afterwards - // crashes on some platforms, notably OSX - - d.errorMsg = 0; - d.fork = fork(); - switch(d.fork) { - case -1: - perror("kdeinit4: fork() failed"); - d.result = 3; - d.errorMsg = i18n("Unable to create new process.\n" - "The system may have reached the maximum number of processes possible or the maximum number of processes that you are allowed to use has been reached.").toUtf8(); - close(d.fd[0]); - close(d.fd[1]); - d.fork = 0; - break; - case 0: - { - // Child - close(d.fd[0]); - close_fds(); - - // Try to chdir, either to the requested directory or to the user's document path by default. - // We ignore errors - if you write a desktop file with Exec=foo and Path=/doesnotexist, - // we still want to execute `foo` even if the chdir() failed. - if (cwd && *cwd) { - (void)chdir(cwd); - } - - for (int i = 0; i < envc; i++) - { - putenv((char *)envs); - while(*envs != 0) envs++; - envs++; - } - -#ifdef Q_WS_X11 - if( startup_id.none()) - KStartupInfo::resetStartupEnv(); - else - startup_id.setupStartupEnv(); -#endif - { - int r; - QByteArray procTitle; - d.argv = (char **) malloc(sizeof(char *) * (argc+1)); - d.argv[0] = (char *) _name; - for (int i = 1; i < argc; i++) - { - d.argv[i] = (char *) args; - procTitle += ' '; - procTitle += (char *) args; - while(*args != 0) args++; - args++; - } - d.argv[argc] = 0; - -#ifndef SKIP_PROCTITLE - // Give the process a new name -#ifdef Q_OS_LINUX - // Set the process name so that killall works like intended - r = prctl(PR_SET_NAME, (unsigned long) name.data(), 0, 0, 0); - if ( r == 0 ) - proctitle_set( "%s [kdeinit]%s", name.data(), procTitle.data() ? procTitle.data() : "" ); - else - proctitle_set( "kdeinit4: %s%s", name.data(), procTitle.data() ? procTitle.data() : "" ); -#else - proctitle_set( "kdeinit4: %s%s", name.data(), procTitle.data() ? procTitle.data() : "" ); -#endif -#endif - } - - if (libpath.isEmpty() && execpath.isEmpty()) - { - QString errorMsg = i18n("Could not find '%1' executable.", QFile::decodeName(_name)); - exitWithErrorMsg(errorMsg); - } - - QLibrary l(libpath); - - if ( !libpath.isEmpty() ) - { - if (!l.load() || !l.isLoaded() ) - { - QString ltdlError (l.errorString()); - if (execpath.isEmpty()) - { - // Error - QString errorMsg = i18n("Could not open library '%1'.\n%2", libpath, ltdlError); - exitWithErrorMsg(errorMsg); - } - else - { - // Print warning - fprintf(stderr, "Could not open library %s: %s\n", qPrintable(lib), - qPrintable(ltdlError) ); - } - } - } - if (!l.isLoaded()) - { - d.result = 2; // Try execing - write(d.fd[1], &d.result, 1); - - // We set the close on exec flag. - // Closing of d.fd[1] indicates that the execvp succeeded! - fcntl(d.fd[1], F_SETFD, FD_CLOEXEC); - - setup_tty( tty ); - - if (!execpath.isEmpty()) - execvp(execpath.constData(), d.argv); - - d.result = 1; // Error - write(d.fd[1], &d.result, 1); - close(d.fd[1]); - exit(255); - } - - void * sym = l.resolve( "kdemain" ); - if ( !sym ) - { - QString ltdlError = l.errorString(); - fprintf(stderr, "Could not find kdemain: %s\n", qPrintable(ltdlError) ); - QString errorMsg = i18n("Could not find 'kdemain' in '%1'.\n%2", - libpath, ltdlError); - exitWithErrorMsg(errorMsg); - } - - d.result = 0; // Success - write(d.fd[1], &d.result, 1); - close(d.fd[1]); - - d.func = (int (*)(int, char *[])) sym; - if (d.debug_wait) - { - fprintf(stderr, "kdeinit4: Suspending process\n" - "kdeinit4: 'gdb kdeinit4 %d' to debug\n" - "kdeinit4: 'kill -SIGCONT %d' to continue\n", - getpid(), getpid()); - kill(getpid(), SIGSTOP); - } - else - { - setup_tty( tty ); - } - - exit( d.func(argc, d.argv)); /* Launch! */ - - break; - } - default: - // Parent - close(d.fd[1]); - bool exec = false; - for(;;) - { - d.n = read(d.fd[0], &d.result, 1); - if (d.n == 1) - { - if (d.result == 2) - { -#ifndef NDEBUG - //fprintf(stderr, "kdeinit4: no kdeinit module, trying exec....\n"); -#endif - exec = true; - continue; - } - if (d.result == 3) - { - int l = 0; - d.n = read(d.fd[0], &l, sizeof(int)); - if (d.n == sizeof(int)) - { - QByteArray tmp; - tmp.resize(l+1); - d.n = read(d.fd[0], tmp.data(), l); - tmp[l] = 0; - if (d.n == l) - d.errorMsg = tmp; - } - } - // Finished - break; - } - if (d.n == -1) - { - if (errno == ECHILD) { // a child died. - continue; - } - if (errno == EINTR || errno == EAGAIN) { // interrupted or more to read - continue; - } - } - if (d.n == 0) - { - if (exec) { - d.result = 0; - } else { - fprintf(stderr,"kdeinit4: (%s %s) Pipe closed unexpectedly", name.constData(), execpath.constData()); - perror("kdeinit4: Pipe closed unexpectedly"); - d.result = 1; // Error - } - break; - } - perror("kdeinit4: Error reading from pipe"); - d.result = 1; // Error - break; - } - close(d.fd[0]); - } -#ifdef Q_WS_X11 - if( !startup_id.none()) - { - if( d.fork && d.result == 0 ) // launched successfully - complete_startup_info( startup_id, d.fork ); - else // failure, cancel ASN - complete_startup_info( startup_id, 0 ); - } -#endif - return d.fork; -} - -extern "C" { - -static void sig_child_handler(int) -{ - /* - * Write into the pipe of death. - * This way we are sure that we return from the select() - * - * A signal itself causes select to return as well, but - * this creates a race-condition in case the signal arrives - * just before we enter the select. - */ - char c = 0; - write(d.deadpipe[1], &c, 1); -} - -} - -static void init_signals() -{ - struct sigaction act; - long options; - - if (pipe(d.deadpipe) != 0) - { - perror("kdeinit4: Aborting. Can not create pipe"); - exit(255); - } - - options = fcntl(d.deadpipe[0], F_GETFL); - if (options == -1) - { - perror("kdeinit4: Aborting. Can not make pipe non-blocking"); - exit(255); - } - - if (fcntl(d.deadpipe[0], F_SETFL, options | O_NONBLOCK) == -1) - { - perror("kdeinit4: Aborting. Can not make pipe non-blocking"); - exit(255); - } - - /* - * A SIGCHLD handler is installed which sends a byte into the - * pipe of death. This is to ensure that a dying child causes - * an exit from select(). - */ - act.sa_handler=sig_child_handler; - sigemptyset(&(act.sa_mask)); - sigaddset(&(act.sa_mask), SIGCHLD); - sigprocmask(SIG_UNBLOCK, &(act.sa_mask), 0L); - act.sa_flags = SA_NOCLDSTOP; - - // CC: take care of SunOS which automatically restarts interrupted system - // calls (and thus does not have SA_RESTART) - -#ifdef SA_RESTART - act.sa_flags |= SA_RESTART; -#endif - sigaction( SIGCHLD, &act, 0L); - - act.sa_handler=SIG_IGN; - sigemptyset(&(act.sa_mask)); - sigaddset(&(act.sa_mask), SIGPIPE); - sigprocmask(SIG_UNBLOCK, &(act.sa_mask), 0L); - act.sa_flags = 0; - sigaction( SIGPIPE, &act, 0L); -} - -static void shutdown_kdeinit() -{ - QT_SOCKLEN_T socklen; - - /** Test if socket file is already present - * note that access() resolves symlinks, and so we check the actual - * socket file if it exists - */ - if (access(sock_file, W_OK) == 0) - { - int s; - struct sockaddr_un server; - -// fprintf(stderr, "kdeinit4: Warning, socket_file already exists!\n"); - // Create the socket stream - s = socket(PF_UNIX, SOCK_STREAM, 0); - if (s < 0) - { - perror("socket() failed"); - exit(255); - } - server.sun_family = AF_UNIX; - strcpy(server.sun_path, sock_file); - socklen = sizeof(server); - - if(connect(s, (struct sockaddr *)&server, socklen) == 0) - { - fprintf(stderr, "kdeinit4: Shutting down running client.\n"); - klauncher_header request_header; - request_header.cmd = LAUNCHER_TERMINATE_KDEINIT; - request_header.arg_length = 0; - write(s, &request_header, sizeof(request_header)); - sleep(1); // Give it some time - } - close(s); - } - - // Delete any stale socket file (and symlink) - unlink(sock_file); -} - -static void init_kdeinit_socket() -{ - struct sockaddr_un sa; - QT_SOCKLEN_T socklen; - long options; - const QByteArray home_dir = qgetenv("HOME"); - int max_tries = 10; - if (home_dir.isEmpty()) - { - fprintf(stderr, "kdeinit4: Aborting. $HOME not set!"); - exit(255); - } - if (chdir(home_dir) != 0) { - fprintf(stderr, "kdeinit4: Aborting. Couldn't enter '%s'!", home_dir.constData()); - exit(255); - } - - { - QByteArray path = home_dir; - QByteArray readOnly = qgetenv("KDE_HOME_READONLY"); - if (access(path.data(), R_OK|W_OK)) - { - if (errno == ENOENT) - { - fprintf(stderr, "kdeinit4: Aborting. $HOME directory (%s) does not exist.\n", path.data()); - exit(255); - } - else if (readOnly.isEmpty()) - { - fprintf(stderr, "kdeinit4: Aborting. No write access to $HOME directory (%s).\n", path.data()); - exit(255); - } - } -#if 0 // obsolete in kde4. Should we check writing to another file instead? - path = qgetenv("ICEAUTHORITY"); - if (path.isEmpty()) - { - path = home_dir; - path += "/.ICEauthority"; - } - if (access(path.data(), R_OK|W_OK) && (errno != ENOENT)) - { - fprintf(stderr, "kdeinit4: Aborting. No write access to '%s'.\n", path.data()); - exit(255); - } -#endif - } - - shutdown_kdeinit(); - - // Create socket - d.wrapper = socket(PF_UNIX, SOCK_STREAM, 0); - if (d.wrapper < 0) - { - perror("kdeinit4: Aborting. socket() failed"); - exit(255); - } - - options = fcntl(d.wrapper, F_GETFL); - if (options == -1) - { - perror("kdeinit4: Aborting. Can not make socket non-blocking"); - close(d.wrapper); - exit(255); - } - - if (fcntl(d.wrapper, F_SETFL, options | O_NONBLOCK) == -1) - { - perror("kdeinit4: Aborting. Can not make socket non-blocking"); - close(d.wrapper); - exit(255); - } - - while (1) { - // Bind it - socklen = sizeof(sa); - memset(&sa, 0, socklen); - sa.sun_family = AF_UNIX; - strcpy(sa.sun_path, sock_file); - if(bind(d.wrapper, (struct sockaddr *)&sa, socklen) != 0) - { - if (max_tries == 0) { - perror("kdeinit4: Aborting. bind() failed"); - fprintf(stderr, "Could not bind to socket '%s'\n", sock_file); - close(d.wrapper); - exit(255); - } - max_tries--; - } else - break; - } - - // Set permissions - if (chmod(sock_file, 0600) != 0) - { - perror("kdeinit4: Aborting. Can not set permissions on socket"); - fprintf(stderr, "Wrong permissions of socket '%s'\n", sock_file); - unlink(sock_file); - close(d.wrapper); - exit(255); - } - - if(listen(d.wrapper, SOMAXCONN) < 0) - { - perror("kdeinit4: Aborting. listen() failed"); - unlink(sock_file); - close(d.wrapper); - exit(255); - } -} - -/* - * 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 void start_klauncher() -{ - if (socketpair(AF_UNIX, SOCK_STREAM, 0, d.launcher) < 0) { - perror("kdeinit4: socketpair() failed"); - exit(255); - } - char args[32]; - strcpy(args, "--fd="); - sprintf(args + 5, "%d", d.launcher[1]); - d.launcher_pid = launch( 2, "klauncher", args ); - close(d.launcher[1]); -#ifndef NDEBUG - fprintf(stderr, "kdeinit4: Launched KLauncher, pid = %ld, result = %d\n", - (long) d.launcher_pid, d.result); -#endif -} - -static void launcher_died() -{ - if (!d.launcher_ok) - { - /* This is bad. */ - fprintf(stderr, "kdeinit4: Communication error with launcher. Exiting!\n"); - ::exit(255); - return; - } - - // KLauncher died... restart -#ifndef NDEBUG - fprintf(stderr, "kdeinit4: KLauncher died unexpectedly.\n"); -#endif - // Make sure it's really dead. - if (d.launcher_pid) - { - kill(d.launcher_pid, SIGKILL); - sleep(1); // Give it some time - } - - d.launcher_ok = false; - d.launcher_pid = 0; - close(d.launcher[0]); - d.launcher[0] = -1; - - start_klauncher(); -} - -static bool handle_launcher_request(int sock, const char *who) -{ - (void)who; // for NDEBUG - - klauncher_header request_header; - char *request_data = 0L; - int result = read_socket(sock, (char *) &request_header, sizeof(request_header)); - if (result != 0) - { - return false; - } - - if ( request_header.arg_length != 0 ) - { - request_data = (char *) malloc(request_header.arg_length); - - result = read_socket(sock, request_data, request_header.arg_length); - if (result != 0) - { - free(request_data); - return false; - } - } - - //kDebug() << "Got cmd" << request_header.cmd << commandToString(request_header.cmd); - if (request_header.cmd == LAUNCHER_OK) - { - d.launcher_ok = true; - } - else if (request_header.arg_length && - ((request_header.cmd == LAUNCHER_EXEC_ASN) || - (request_header.cmd == LAUNCHER_EXEC))) - { - pid_t pid; - klauncher_header response_header; - long response_data; - long l; - memcpy( &l, request_data, sizeof( long )); - int argc = l; - const char *name = request_data + sizeof(long); - const char *args = name + strlen(name) + 1; - const char *cwd = 0; - int envc = 0; - const char *envs = 0; - const char *tty = 0; - int avoid_loops = 0; - const char *startup_id_str = "0"; // krazy:exclude=doublequote_chars - -#ifndef NDEBUG - fprintf(stderr, "kdeinit4: Got %s '%s' from %s.\n", - commandToString(request_header.cmd), - name, who); -#endif - - const char *arg_n = args; - for(int i = 1; i < argc; i++) - { - arg_n = arg_n + strlen(arg_n) + 1; - } - - memcpy( &l, arg_n, sizeof( long )); - envc = l; - arg_n += sizeof(long); - envs = arg_n; - for(int i = 0; i < envc; i++) - { - arg_n = arg_n + strlen(arg_n) + 1; - } - memcpy( &l, arg_n, sizeof( long )); - avoid_loops = l; - arg_n += sizeof( long ); - - if( request_header.cmd == LAUNCHER_EXEC_ASN ) - { - startup_id_str = arg_n; - arg_n += strlen( startup_id_str ) + 1; - } - - if (request_header.arg_length > (arg_n - request_data)) - { - // Optional cwd - cwd = arg_n; arg_n += strlen(cwd) + 1; - } - - if ((arg_n - request_data) != request_header.arg_length) - { -#ifndef NDEBUG - fprintf(stderr, "kdeinit4: EXEC request has invalid format.\n"); -#endif - free(request_data); - d.debug_wait = false; - return true; // sure? - } - - pid = launch( argc, name, args, cwd, envc, envs, - tty, avoid_loops, startup_id_str ); - - if (pid && (d.result == 0)) - { - response_header.cmd = LAUNCHER_OK; - response_header.arg_length = sizeof(response_data); - response_data = pid; - write(sock, &response_header, sizeof(response_header)); - write(sock, &response_data, response_header.arg_length); - - /* add new child to list */ - struct child *child = (struct child *) malloc(sizeof(struct child)); - child->pid = pid; - child->sock = dup(sock); - child->next = children; - children = child; - } - else - { - int l = d.errorMsg.length(); - if (l) l++; // Include trailing null. - response_header.cmd = LAUNCHER_ERROR; - response_header.arg_length = l; - write(sock, &response_header, sizeof(response_header)); - if (l) - write(sock, d.errorMsg.data(), l); - } - d.debug_wait = false; - } - else if (request_header.arg_length && request_header.cmd == LAUNCHER_SETENV) - { - const char *env_name; - const char *env_value; - env_name = request_data; - env_value = env_name + strlen(env_name) + 1; - -#ifndef NDEBUG - fprintf(stderr, "kdeinit4: Got SETENV '%s=%s' from %s.\n", env_name, env_value, who); -#endif - - if ( request_header.arg_length != - (int) (strlen(env_name) + strlen(env_value) + 2)) - { -#ifndef NDEBUG - fprintf(stderr, "kdeinit4: SETENV request has invalid format.\n"); -#endif - free(request_data); - return true; // sure? - } - setenv( env_name, env_value, 1); - } - else if (request_header.cmd == LAUNCHER_TERMINATE_KDEINIT) - { -#ifndef NDEBUG - fprintf(stderr,"kdeinit4: Got termination request (PID %ld).\n", (long) getpid()); -#endif - if (d.launcher_pid) { - kill(d.launcher_pid, SIGTERM); - d.launcher_pid = 0; - close(d.launcher[0]); - d.launcher[0] = -1; - } - unlink(sock_file); - if (children) { - close(d.wrapper); - d.wrapper = -1; -#ifndef NDEBUG - fprintf(stderr,"kdeinit4: Closed sockets, but not exiting until all children terminate.\n"); -#endif - } else { - raise(SIGTERM); - } - } - else if (request_header.cmd == LAUNCHER_DEBUG_WAIT) - { -#ifndef NDEBUG - fprintf(stderr,"kdeinit4: Debug wait activated.\n"); -#endif - d.debug_wait = true; - } - if (request_data) - free(request_data); - return true; -} - -static void handle_requests(pid_t waitForPid) -{ - int max_sock = d.deadpipe[0]; - if (d.wrapper > max_sock) - max_sock = d.wrapper; - if (d.launcher[0] > max_sock) - max_sock = d.launcher[0]; -#ifdef Q_WS_X11 - if (X11fd > max_sock) - max_sock = X11fd; -#endif - max_sock++; - - while(1) - { - fd_set rd_set; - fd_set wr_set; - fd_set e_set; - int result; - pid_t exit_pid; - int exit_status; - char c; - - /* Flush the pipe of death */ - while( read(d.deadpipe[0], &c, 1) == 1) - {} - - /* Handle dying children */ - do { - exit_pid = waitpid(-1, &exit_status, WNOHANG); - if (exit_pid > 0) - { -#ifndef NDEBUG - fprintf(stderr, "kdeinit4: PID %ld terminated.\n", (long) exit_pid); -#endif - if (waitForPid && (exit_pid == waitForPid)) - return; - - if( WIFEXITED( exit_status )) // fix process return value - exit_status = WEXITSTATUS(exit_status); - else if( WIFSIGNALED(exit_status)) - exit_status = 128 + WTERMSIG( exit_status ); - child_died(exit_pid, exit_status); - - if (d.wrapper < 0 && !children) { -#ifndef NDEBUG - fprintf(stderr, "kdeinit4: Last child terminated, exiting (PID %ld).\n", - (long) getpid()); -#endif - raise(SIGTERM); - } - } - } - while( exit_pid > 0); - - FD_ZERO(&rd_set); - FD_ZERO(&wr_set); - FD_ZERO(&e_set); - - if (d.launcher[0] >= 0) - FD_SET(d.launcher[0], &rd_set); - if (d.wrapper >= 0) - FD_SET(d.wrapper, &rd_set); - FD_SET(d.deadpipe[0], &rd_set); -#ifdef Q_WS_X11 - if(X11fd >= 0) FD_SET(X11fd, &rd_set); -#endif - - result = select(max_sock, &rd_set, &wr_set, &e_set, 0); - if (result < 0) { - if (errno == EINTR || errno == EAGAIN) - continue; - perror("kdeinit4: Aborting. select() failed"); - return; - } - - /* Handle wrapper request */ - if (d.wrapper >= 0 && FD_ISSET(d.wrapper, &rd_set)) - { - struct sockaddr_un client; - QT_SOCKLEN_T sClient = sizeof(client); - int sock = accept(d.wrapper, (struct sockaddr *)&client, &sClient); - if (sock >= 0) - { - d.accepted_fd = sock; - handle_launcher_request(sock, "wrapper"); - close(sock); - d.accepted_fd = -1; - } - } - - /* Handle launcher request */ - if (d.launcher[0] >= 0 && FD_ISSET(d.launcher[0], &rd_set)) - { - if (!handle_launcher_request(d.launcher[0], "launcher")) - launcher_died(); - if (waitForPid == d.launcher_pid) - return; - } - -#ifdef Q_WS_X11 - /* Look for incoming X11 events */ - if(X11fd >= 0 && FD_ISSET(X11fd,&rd_set)) { - if (X11display != 0) { - XEvent event_return; - while (XPending(X11display)) - XNextEvent(X11display, &event_return); - } - } -#endif - } -} - -static void kdeinit_library_path() -{ - QByteArray display = qgetenv(DISPLAY); - if (display.isEmpty()) - { -#if defined(Q_WS_X11) || defined(Q_WS_QWS) - fprintf(stderr, "kdeinit4: Aborting. $" DISPLAY " is not set.\n"); - exit(255); -#endif - } - int i; - if((i = display.lastIndexOf('.')) > display.lastIndexOf(':') && i >= 0) - display.truncate(i); - - display.replace(':','_'); - // WARNING, if you change the socket name, adjust kwrapper too - const QString socketFileName = QString::fromLatin1("kdeinit4_%1").arg(QLatin1String(display)); - QByteArray socketName = QFile::encodeName(KStandardDirs::locateLocal("tmp", socketFileName, *s_instance)); - if (socketName.length() >= MAX_SOCK_FILE) - { - fprintf(stderr, "kdeinit4: Aborting. Socket name will be too long:\n"); - fprintf(stderr, " '%s'\n", socketName.data()); - exit(255); - } - strcpy(sock_file, socketName.data()); -} - -int kdeinit_xio_errhandler( Display *disp ) -{ - // disp is 0L when KDE shuts down. We don't want those warnings then. - if ( disp ) - kWarning() << "Fatal IO error: client killed"; - - if (sock_file[0]) - { - // Delete any stale socket file - unlink(sock_file); - } - - // Don't kill our children in suicide mode, they may still be in use - if (d.suicide) - { - if (d.launcher_pid) - kill(d.launcher_pid, SIGTERM); - exit( 0 ); - } - - if ( disp ) - kWarning() << "Sending SIGHUP to children."; - - // this should remove all children we started - KDE_signal(SIGHUP, SIG_IGN); - kill(0, SIGHUP); - - sleep(2); - - if ( disp ) - kWarning() << "Sending SIGTERM to children."; - - // And if they don't listen to us, this should work - KDE_signal(SIGTERM, SIG_IGN); - kill(0, SIGTERM); - - if ( disp ) - kWarning() << "Exit."; - - exit( 0 ); - return 0; -} - -#ifdef Q_WS_X11 -int kdeinit_x_errhandler( Display *dpy, XErrorEvent *err ) -{ -#ifndef NDEBUG - char errstr[256]; - // kdeinit almost doesn't use X, and therefore there shouldn't be any X error - XGetErrorText( dpy, err->error_code, errstr, 256 ); - fprintf(stderr, "kdeinit4(%d) : KDE detected X Error: %s %d\n" - " Major opcode: %d\n" - " Minor opcode: %d\n" - " Resource id: 0x%lx\n", - getpid(), errstr, err->error_code, err->request_code, err->minor_code, err->resourceid ); - - //kDebug() << kBacktrace(); - -#else - Q_UNUSED(dpy); - Q_UNUSED(err); -#endif - return 0; -} -#endif - -#ifdef Q_WS_X11 -// needs to be done sooner than initXconnection() because of also opening -// another X connection for startup notification purposes -static void setupX() -{ - XSetIOErrorHandler(kdeinit_xio_errhandler); - XSetErrorHandler(kdeinit_x_errhandler); -} - -// Borrowed from kdebase/kaudio/kaudioserver.cpp -static int initXconnection() -{ - X11display = XOpenDisplay(NULL); - if ( X11display != 0 ) { - XCreateSimpleWindow(X11display, DefaultRootWindow(X11display), 0,0,1,1, \ - 0, - BlackPixelOfScreen(DefaultScreenOfDisplay(X11display)), - BlackPixelOfScreen(DefaultScreenOfDisplay(X11display)) ); -#ifndef NDEBUG - fprintf(stderr, "kdeinit4: opened connection to %s\n", DisplayString(X11display)); -#endif - int fd = XConnectionNumber( X11display ); - int on = 1; - (void) setsockopt(fd, SOL_SOCKET, SO_KEEPALIVE, (char *) &on, (int) sizeof(on)); - return fd; - } else - fprintf(stderr, "kdeinit4: Can not connect to the X Server.\n" \ - "kdeinit4: Might not terminate at end of session.\n"); - - return -1; -} -#endif - -extern "C" { - -static void secondary_child_handler(int) -{ - waitpid(-1, 0, WNOHANG); -} - -} - -int main(int argc, char **argv) -{ - setlocale (LC_ALL, ""); - setlocale (LC_NUMERIC, "C"); - - pid_t pid; - bool do_fork = true; - int launch_klauncher = 1; - int do_shutdown = 0; - d.suicide = false; - - // Check arguments first... - for(int i = 0; i < argc; i++) - { - if (strcmp(argv[i], "--no-klauncher") == 0) - launch_klauncher = 0; - if (strcmp(argv[i], "--no-fork") == 0) - do_fork = false; - if (strcmp(argv[i], "--suicide") == 0) - d.suicide = true; - if (strcmp(argv[i], "--shutdown") == 0) - do_shutdown = 1; - if (strcmp(argv[i], "--version") == 0) - { - printf("Katie: %s\n", qVersion()); - printf("KDE: %s\n", KDE_VERSION_STRING); - exit(0); - } - if (strcmp(argv[i], "--help") == 0) - { - printf("Usage: kdeinit4 [options]\n"); - printf(" --no-fork Do not fork\n"); - printf(" --no-klauncher Do not start klauncher\n"); - printf(" --suicide Terminate when no KDE applications are left running\n"); - printf(" --version Show version information\n"); - printf(" --shutdown Shutdown running kdeinit4 instance\n"); - exit(0); - } - } - - if (do_shutdown) { - KDE_signal(SIGPIPE, SIG_IGN); - s_instance = new KComponentData("kdeinit4", QByteArray(), KComponentData::SkipMainComponentRegistration); - kdeinit_library_path(); - shutdown_kdeinit(); - return 0; - } - - cleanup_fds(); - - // Redirect stdout to stderr. We have no reason to use stdout anyway. - // This minimizes our impact on commands used in pipes. - (void)dup2(2, 1); - - if (do_fork) { - if (pipe(d.initpipe) != 0) { - perror("kdeinit4: pipe failed"); - return 1; - } - - // Fork here and let parent process exit. - // Parent process may only exit after all required services have been - // launched. (dcopserver/klauncher and services which start with '+') - KDE_signal( SIGCHLD, secondary_child_handler); - if (fork() > 0) // Go into background - { - close(d.initpipe[1]); - d.initpipe[1] = -1; - // wait till init is complete - char c; - while( read(d.initpipe[0], &c, 1) < 0) - ; - // then exit; - close(d.initpipe[0]); - d.initpipe[0] = -1; - return 0; - } - close(d.initpipe[0]); - d.initpipe[0] = -1; - } - - // Make process group leader (for shutting down children later) - setsid(); - - // Create our instance - s_instance = new KComponentData("kdeinit4", QByteArray(), KComponentData::SkipMainComponentRegistration); - - // Prepare to change process name -#ifndef SKIP_PROCTITLE - proctitle_init(argc, argv); -#endif - - kdeinit_library_path(); - // Don't make our instance the global instance - // (do it only after kdeinit_library_path, that one indirectly uses KConfig, - // which seems to be buggy and always use KGlobal instead of the matching KComponentData) - Q_ASSERT(!KGlobal::hasMainComponent()); - KApplication::loadedByKdeinit = true; - - d.maxname = strlen(argv[0]); - d.launcher_pid = 0; - d.wrapper = -1; - d.accepted_fd = -1; - d.debug_wait = false; - d.launcher_ok = false; - children = NULL; - init_signals(); -#ifdef Q_WS_X11 - setupX(); -#endif - - // Create socket for incoming wrapper requests - init_kdeinit_socket(); - - if (launch_klauncher) - { - start_klauncher(); - handle_requests(d.launcher_pid); // Wait for klauncher to be ready - } - -#ifdef Q_WS_X11 - X11fd = initXconnection(); -#endif - -#ifndef SKIP_PROCTITLE - proctitle_set("kdeinit4 Running..."); -#endif - - if (d.initpipe[1] != -1) - { - char c = 0; - write(d.initpipe[1], &c, 1); // Kdeinit is started. - close(d.initpipe[1]); - d.initpipe[1] = -1; - } - - handle_requests(0); - - return 0; -} - - diff --git a/kinit/klauncher.cpp b/kinit/klauncher.cpp index d17cba9c..7c563b9f 100644 --- a/kinit/klauncher.cpp +++ b/kinit/klauncher.cpp @@ -1,1217 +1,97 @@ -/* - This file is part of the KDE libraries - Copyright (c) 1999 Waldo Bastian +/* This file is part of the KDE libraries + Copyright (C) 2022 Ivailo Monev - 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. */ -#define QT_NO_CAST_FROM_ASCII - #include "klauncher.h" -#include "klauncher_cmds.h" #include "klauncher_adaptor.h" +#include "kaboutdata.h" +#include "kdeversion.h" +#include "kapplication.h" +#include "kcmdlineargs.h" +#include "kdebug.h" -#include +#include +#include +#include -#include -#include -#include -#include -#include -#include - -#ifdef Q_WS_X11 -#include -#include -#endif - -#include -#include -#include - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include - -// Dispose slaves after being idle for SLAVE_MAX_IDLE seconds -#define SLAVE_MAX_IDLE 30 - -// #define KLAUNCHER_VERBOSE_OUTPUT - -#ifdef KLAUNCHER_VERBOSE_OUTPUT -static const char* const s_DBusStartupTypeToString[] = - { "DBusNone", "DBusUnique", "DBusMulti", "DBusWait", "ERROR" }; -#endif - -using namespace KIO; - -IdleSlave::IdleSlave(QObject *parent) +KLauncher::KLauncher(QObject *parent) : QObject(parent) { - QObject::connect(&mConn, SIGNAL(readyRead()), this, SLOT(gotInput())); - // Send it a SLAVE_STATUS command. - mConn.send( CMD_SLAVE_STATUS ); - mPid = 0; - mBirthDate = time(0); - mOnHold = false; -} + m_adaptor = new KLauncherAdaptor(this); -void -IdleSlave::gotInput() -{ - int cmd; - QByteArray data; - if (mConn.read( &cmd, data) == -1) - { - // Communication problem with slave. - // kError(7016) << "No communication with slave."; - deleteLater(); - } - else if (cmd == MSG_SLAVE_ACK) - { - deleteLater(); - } - else if (cmd != MSG_SLAVE_STATUS) - { - kError(7016) << "Unexpected data from slave."; - deleteLater(); - } - else - { - QDataStream stream( data ); - qint64 pid; - QByteArray protocol; - QString host; - qint8 b; - stream >> pid >> protocol >> host >> b; - // Overload with (bool) onHold, (KUrl) url. - if (!stream.atEnd()) - { - KUrl url; - stream >> url; - mOnHold = true; - mUrl = url; - } - - mPid = static_cast(pid); - mConnected = (b != 0); - mProtocol = QString::fromLatin1(protocol); - mHost = host; - emit statusUpdate(this); - } -} - -void -IdleSlave::connect(const QString &app_socket) -{ - QByteArray data; - QDataStream stream( &data, QIODevice::WriteOnly); - stream << app_socket; - mConn.send( CMD_SLAVE_CONNECT, data ); - // Timeout! -} - -void -IdleSlave::reparseConfiguration() -{ - mConn.send( CMD_REPARSECONFIGURATION ); -} - -bool -IdleSlave::match(const QString &protocol, const QString &host, bool needConnected) const -{ - if (mOnHold || protocol != mProtocol) { - return false; - } - if (host.isEmpty()) { - return true; - } - return (host == mHost) && (!needConnected || mConnected); -} - -bool -IdleSlave::onHold(const KUrl &url) const -{ - if (!mOnHold) return false; - return (url == mUrl); -} - -int -IdleSlave::age(time_t now) const -{ - return (int) difftime(now, mBirthDate); -} - -static KLauncher* g_klauncher_self = NULL; - - -// From qcore_unix_p.h. We could also port to QLocalSocket :) -#define K_EINTR_LOOP(var, cmd) \ - do { \ - var = cmd; \ - } while (var == -1 && errno == EINTR) - -ssize_t kde_safe_write(int fd, const void *buf, size_t count) -{ - ssize_t ret = 0; - K_EINTR_LOOP(ret, QT_WRITE(fd, buf, count)); - if (ret < 0) - kWarning() << "write failed:" << strerror(errno); - return ret; -} - -KLauncher::KLauncher(int _kdeinitSocket) - : QObject(0), - kdeinitSocket(_kdeinitSocket) -{ -#ifdef Q_WS_X11 - mCached_dpy = NULL; -#endif - Q_ASSERT( g_klauncher_self == NULL ); - g_klauncher_self = this; - - mAutoTimer.setSingleShot(true); - new KLauncherAdaptor(this); - QDBusConnection::sessionBus().registerObject(QLatin1String("/KLauncher"), this); // same as ktoolinvocation.cpp - - connect(&mAutoTimer, SIGNAL(timeout()), this, SLOT(slotAutoStart())); - connect(QDBusConnection::sessionBus().interface(), - SIGNAL(serviceOwnerChanged(QString,QString,QString)), - SLOT(slotNameOwnerChanged(QString,QString,QString))); - - mConnectionServer.listenForRemote(); - connect(&mConnectionServer, SIGNAL(newConnection()), SLOT(acceptSlave())); - if (!mConnectionServer.isListening()) - { - // Severe error! - kDebug() << "Fatal error, can't create tempfile!"; - ::_exit(1); - } - - connect(&mTimer, SIGNAL(timeout()), SLOT(idleTimeout())); - - kdeinitNotifier = new QSocketNotifier(kdeinitSocket, QSocketNotifier::Read); - connect(kdeinitNotifier, SIGNAL(activated(int)), - this, SLOT(slotKDEInitData(int))); - kdeinitNotifier->setEnabled( true ); - lastRequest = 0; - bProcessingQueue = false; - - mSlaveDebug = QString::fromLocal8Bit(qgetenv("KDE_SLAVE_DEBUG_WAIT")); - if (!mSlaveDebug.isEmpty()) - { - kWarning() << "Running in slave-debug mode for slaves of protocol:" << qPrintable(mSlaveDebug); - } - mSlaveValgrind = QString::fromLocal8Bit(qgetenv("KDE_SLAVE_VALGRIND")); - if (!mSlaveValgrind.isEmpty()) - { - mSlaveValgrindSkin = QString::fromLocal8Bit(qgetenv("KDE_SLAVE_VALGRIND_SKIN")); - kWarning() << "Running slaves through valgrind for slaves of protocol:" << qPrintable(mSlaveValgrind); - } - klauncher_header request_header; - request_header.cmd = LAUNCHER_OK; - request_header.arg_length = 0; - kde_safe_write(kdeinitSocket, &request_header, sizeof(request_header)); + QDBusConnection session = QDBusConnection::sessionBus(); + session.registerObject("/KLauncher", this); + session.registerService("org.kde.klauncher"); } KLauncher::~KLauncher() { - close(); - g_klauncher_self = NULL; + QDBusConnection session = QDBusConnection::sessionBus(); + session.unregisterObject("/KLauncher"); + session.unregisterService("org.kde.klauncher"); } -void KLauncher::close() +void KLauncher::setSessionManager(const QByteArray &sessionmanager) { -#ifdef Q_WS_X11 - if( mCached_dpy != NULL ) - { - XCloseDisplay( mCached_dpy ); - mCached_dpy = NULL; - } -#endif -} - -void -KLauncher::destruct() -{ - if (g_klauncher_self) - g_klauncher_self->close(); - // We don't delete the app here, that's intentional. - ::_exit(255); -} - -void KLauncher::setLaunchEnv(const QString &name, const QString &value) -{ - klauncher_header request_header; - QByteArray requestData; - requestData.append(name.toLocal8Bit()).append('\0').append(value.toLocal8Bit()).append('\0'); - request_header.cmd = LAUNCHER_SETENV; - request_header.arg_length = requestData.size(); - kde_safe_write(kdeinitSocket, &request_header, sizeof(request_header)); - kde_safe_write(kdeinitSocket, requestData.data(), request_header.arg_length); -} - -/* - * Read 'len' bytes from 'sock' into buffer. - * returns -1 on failure, 0 on no data. - */ -static int -read_socket(int sock, char *buffer, int len) -{ - ssize_t result; - int bytes_left = len; - while (bytes_left > 0) { - // in case we get a request to start an application and data arrive - // to kdeinitSocket at the same time, requestStart() will already - // call slotKDEInitData(), so we must check there's still something - // to read, otherwise this would block - - // Same thing if kdeinit dies without warning. - - fd_set in; - timeval tm = { 30, 0 }; // 30 seconds timeout, so we're not stuck in case kdeinit dies on us - FD_ZERO ( &in ); - FD_SET( sock, &in ); - select( sock + 1, &in, 0, 0, &tm ); - if( !FD_ISSET( sock, &in )) { - kDebug(7016) << "read_socket" << sock << "nothing to read, kdeinit4 must be dead"; - return -1; - } - - 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)) - return -1; - } - return 0; -} - -void -KLauncher::slotKDEInitData(int) -{ - klauncher_header request_header; - QByteArray requestData; - - int result = read_socket(kdeinitSocket, (char *) &request_header, - sizeof( request_header)); - if (result == -1) - { - kDebug(7016) << "Exiting on read_socket errno:" << errno; - KDE_signal( SIGHUP, SIG_IGN); - KDE_signal( SIGTERM, SIG_IGN); - destruct(); // Exit! - } - requestData.resize(request_header.arg_length); - result = read_socket(kdeinitSocket, (char *) requestData.data(), - request_header.arg_length); - - processRequestReturn(request_header.cmd,requestData); -} - -void KLauncher::processRequestReturn(int status, const QByteArray &requestData) -{ - if (status == LAUNCHER_CHILD_DIED) - { - long *request_data = (long *) requestData.data(); - processDied(request_data[0], request_data[1]); - return; - } - if (lastRequest && (status == LAUNCHER_OK)) - { - long *request_data = (long *) requestData.data(); - lastRequest->pid = (pid_t) (*request_data); - kDebug(7016).nospace() << lastRequest->name << " (pid " << lastRequest->pid << - ") up and running."; - switch(lastRequest->dbus_startup_type) - { - case KService::DBusNone: - lastRequest->status = KLaunchRequest::Running; - break; - case KService::DBusUnique: - case KService::DBusWait: - case KService::DBusMulti: - lastRequest->status = KLaunchRequest::Launching; - break; - } - lastRequest = 0; - return; - } - if (lastRequest && (status == LAUNCHER_ERROR)) - { - lastRequest->status = KLaunchRequest::Error; - kDebug(7016) << lastRequest->name << " failed."; - if (!requestData.isEmpty()) - lastRequest->errorMsg = QString::fromUtf8((char *) requestData.data()); - lastRequest = 0; - return; - } - - kWarning(7016)<< "Unexpected request return" << (unsigned int) status; -} - -void -KLauncher::processDied(pid_t pid, long exitStatus) -{ -#ifdef KLAUNCHER_VERBOSE_OUTPUT - kDebug(7016) << pid << "exitStatus=" << exitStatus; -#else - Q_UNUSED(exitStatus); - // We should probably check the exitStatus for the uniqueapp case? -#endif - foreach (KLaunchRequest *request, requestList) - { -#ifdef KLAUNCHER_VERBOSE_OUTPUT - kDebug(7016) << " had pending request" << request->pid; -#endif - if (request->pid == pid) - { - if (request->dbus_startup_type == KService::DBusWait) - request->status = KLaunchRequest::Done; - else if ((request->dbus_startup_type == KService::DBusUnique) - && QDBusConnection::sessionBus().interface()->isServiceRegistered(request->dbus_name)) { - request->status = KLaunchRequest::Running; -#ifdef KLAUNCHER_VERBOSE_OUTPUT - kDebug(7016) << pid << "running as a unique app"; -#endif - } else { - request->status = KLaunchRequest::Error; -#ifdef KLAUNCHER_VERBOSE_OUTPUT - kDebug(7016) << pid << "died, requestDone. status=" << request->status; -#endif - } - requestDone(request); - return; - } - } -#ifdef KLAUNCHER_VERBOSE_OUTPUT - kDebug(7016) << "found no pending requests for PID" << pid; -#endif -} - -static bool matchesPendingRequest(const QString& appId, const QString& pendingAppId) -{ - // appId just registered, e.g. org.koffice.kword-12345 - // Let's see if this is what pendingAppId (e.g. org.koffice.kword or *.kword) was waiting for. - - const QString newAppId = appId.left(appId.lastIndexOf(QLatin1Char('-'))); // strip out the -12345 if present. - - //kDebug() << "appId=" << appId << "newAppId=" << newAppId << "pendingAppId=" << pendingAppId; - - if (pendingAppId.startsWith(QLatin1String("*."))) { - const QString pendingName = pendingAppId.mid(2); - const QString appName = newAppId.mid(newAppId.lastIndexOf(QLatin1Char('.'))+1); - //kDebug() << "appName=" << appName; - return appName == pendingName; - } - - return newAppId == pendingAppId; -} - -void -KLauncher::slotNameOwnerChanged(const QString &appId, const QString &oldOwner, - const QString &newOwner) -{ - Q_UNUSED(oldOwner); - if (appId.isEmpty() || newOwner.isEmpty()) - return; - -#ifdef KLAUNCHER_VERBOSE_OUTPUT - kDebug(7016) << "new app" << appId; -#endif - foreach (KLaunchRequest *request, requestList) - { - if (request->status != KLaunchRequest::Launching) - continue; - -#ifdef KLAUNCHER_VERBOSE_OUTPUT - kDebug(7016) << "had pending request" << request->name << s_DBusStartupTypeToString[request->dbus_startup_type] << "dbus_name" << request->dbus_name << request->tolerant_dbus_name; -#endif - // For unique services check the requested service name first - if (request->dbus_startup_type == KService::DBusUnique) { - if ((appId == request->dbus_name) || // just started - QDBusConnection::sessionBus().interface()->isServiceRegistered(request->dbus_name)) { // was already running - request->status = KLaunchRequest::Running; -#ifdef KLAUNCHER_VERBOSE_OUTPUT - kDebug(7016) << "OK, unique app" << request->dbus_name << "is running"; -#endif - requestDone(request); - continue; - } else { -#ifdef KLAUNCHER_VERBOSE_OUTPUT - kDebug(7016) << "unique app" << request->dbus_name << "not running yet"; -#endif - } - } - - const QString rAppId = !request->tolerant_dbus_name.isEmpty() ? request->tolerant_dbus_name : request->dbus_name; -#ifdef KLAUNCHER_VERBOSE_OUTPUT - //kDebug(7016) << "using" << rAppId << "for matching"; -#endif - if (rAppId.isEmpty()) - continue; - - if (matchesPendingRequest(appId, rAppId)) { -#ifdef KLAUNCHER_VERBOSE_OUTPUT - kDebug(7016) << "ok, request done"; -#endif - request->dbus_name = appId; - request->status = KLaunchRequest::Running; - requestDone(request); - continue; - } - } -} - -void -KLauncher::autoStart(int phase) -{ - if( mAutoStart.phase() >= phase ) - return; - mAutoStart.setPhase(phase); - if (phase == 0) - mAutoStart.loadAutoStartList(); - mAutoTimer.start(0); -} - -void -KLauncher::slotAutoStart() -{ - KService::Ptr s; - do - { - QString service = mAutoStart.startService(); - if (service.isEmpty()) - { - // Done - if( !mAutoStart.phaseDone()) - { - mAutoStart.setPhaseDone(); - switch( mAutoStart.phase()) - { - case 0: - emit autoStart0Done(); - break; - case 1: - emit autoStart1Done(); - break; - case 2: - emit autoStart2Done(); - break; - } - } - return; - } - s = new KService(service); - } - while (!start_service(s, QStringList(), QStringList(), "0", false, true, QDBusMessage())); - // Loop till we find a service that we can start. -} - -void -KLauncher::requestDone(KLaunchRequest *request) -{ - if ((request->status == KLaunchRequest::Running) || - (request->status == KLaunchRequest::Done)) - { - requestResult.result = 0; - requestResult.dbusName = request->dbus_name; - requestResult.error = QString::fromLatin1(""); // not null, cf assert further down - requestResult.pid = request->pid; - } - else - { - requestResult.result = 1; - requestResult.dbusName.clear(); - requestResult.error = i18n("KDEInit could not launch '%1'", request->name); - if (!request->errorMsg.isEmpty()) - requestResult.error += QString::fromLatin1(":\n") + request->errorMsg; - requestResult.pid = 0; - -#ifdef Q_WS_X11 - if (!request->startup_dpy.isEmpty()) - { - Display* dpy = NULL; - if( (mCached_dpy != NULL) && - (request->startup_dpy == XDisplayString( mCached_dpy ))) - dpy = mCached_dpy; - if( dpy == NULL ) - dpy = XOpenDisplay(request->startup_dpy); - if( dpy ) - { - KStartupInfoId id; - id.initId(request->startup_id); - KStartupInfo::sendFinishX( dpy, id ); - if( mCached_dpy != dpy && mCached_dpy != NULL ) - XCloseDisplay( mCached_dpy ); - mCached_dpy = dpy; - } - } -#endif - } - - if (request->autoStart) - { - mAutoTimer.start(0); - } - - if (request->transaction.type() != QDBusMessage::InvalidMessage) - { - if ( requestResult.dbusName.isNull() ) // null strings can't be sent - requestResult.dbusName.clear(); - Q_ASSERT( !requestResult.error.isNull() ); - QDBusConnection::sessionBus().send(request->transaction.createReply(QVariantList() << requestResult.result - << requestResult.dbusName - << requestResult.error - << static_cast(requestResult.pid))); - } -#ifdef KLAUNCHER_VERBOSE_OUTPUT - kDebug(7016) << "removing done request" << request->name << "PID" << request->pid; -#endif - - requestList.removeAll( request ); - delete request; -} - -static void appendLong(QByteArray &ba, long l) -{ - const int sz = ba.size(); - ba.resize(sz + sizeof(long)); - memcpy(ba.data() + sz, &l, sizeof(long)); -} - -void -KLauncher::requestStart(KLaunchRequest *request) -{ - requestList.append( request ); - // Send request to kdeinit. - klauncher_header request_header; - QByteArray requestData; - requestData.reserve(1024); - - appendLong(requestData, request->arg_list.count() + 1); - requestData.append(request->name.toLocal8Bit()); - requestData.append('\0'); - foreach (const QString &arg, request->arg_list) - requestData.append(arg.toLocal8Bit()).append('\0'); - appendLong(requestData, request->envs.count()); - foreach (const QString &env, request->envs) - requestData.append(env.toLocal8Bit()).append('\0'); - appendLong(requestData, 0); // avoid_loops, always false here -#ifdef Q_WS_X11 - bool startup_notify = !request->startup_id.isNull() && request->startup_id != "0"; - if( startup_notify ) - requestData.append(request->startup_id).append('\0'); -#endif - if (!request->cwd.isEmpty()) - requestData.append(QFile::encodeName(request->cwd)).append('\0'); - -#ifdef Q_WS_X11 - request_header.cmd = startup_notify ? LAUNCHER_EXEC_ASN : LAUNCHER_EXEC; -#else - request_header.cmd = LAUNCHER_EXEC; -#endif - request_header.arg_length = requestData.length(); - -#ifdef KLAUNCHER_VERBOSE_OUTPUT - kDebug(7016) << "Asking kdeinit to start" << request->name << request->arg_list - << "cmd=" << commandToString(request_header.cmd); -#endif - - kde_safe_write(kdeinitSocket, &request_header, sizeof(request_header)); - kde_safe_write(kdeinitSocket, requestData.data(), requestData.length()); - - // Wait for pid to return. - lastRequest = request; - do { - slotKDEInitData( kdeinitSocket ); - } - while (lastRequest != 0); -} - -void KLauncher::exec_blind(const QString &name, const QStringList &arg_list) -{ - KLaunchRequest *request = new KLaunchRequest; - request->autoStart = false; - request->name = name; - request->arg_list = arg_list; - request->dbus_startup_type = KService::DBusNone; - request->pid = 0; - request->status = KLaunchRequest::Launching; - request->envs = QStringList(); - - requestStart(request); - // We don't care about this request any longer.... - requestDone(request); -} - -bool -KLauncher::start_service_by_desktop_path(const QString &serviceName, const QStringList &urls, - const QStringList &envs, const QString& startup_id, bool blind, const QDBusMessage &msg) -{ - KService::Ptr service; - // Find service - const QFileInfo fi(serviceName); - if (fi.isAbsolute() && fi.exists()) - { - // Full path - service = new KService(serviceName); - } - else - { - service = KService::serviceByDesktopPath(serviceName); - // TODO? - //if (!service) - // service = KService::serviceByStorageId(serviceName); // This method should be named start_service_by_storage_id ideally... - } - if (!service) - { - requestResult.result = ENOENT; - requestResult.error = i18n("Could not find service '%1'.", serviceName); - cancel_service_startup_info( NULL, startup_id.toLocal8Bit(), envs ); // cancel it if any - return false; - } - return start_service(service, urls, envs, startup_id.toLocal8Bit(), blind, false, msg); -} - -bool -KLauncher::start_service_by_desktop_name(const QString &serviceName, const QStringList &urls, - const QStringList &envs, const QString& startup_id, bool blind, const QDBusMessage &msg) -{ - KService::Ptr service = KService::serviceByDesktopName(serviceName); - if (!service) - { - requestResult.result = ENOENT; - requestResult.error = i18n("Could not find service '%1'.", serviceName); - cancel_service_startup_info( NULL, startup_id.toLocal8Bit(), envs ); // cancel it if any - return false; - } - return start_service(service, urls, envs, startup_id.toLocal8Bit(), blind, false, msg); -} - -bool -KLauncher::start_service(KService::Ptr service, const QStringList &_urls, - const QStringList &envs, const QByteArray &startup_id, - bool blind, bool autoStart, QDBusMessage msg) -{ - QStringList urls = _urls; - bool runPermitted = KDesktopFile::isAuthorizedDesktopFile(service->entryPath()); - - if (!service->isValid() || !runPermitted) - { - requestResult.result = ENOEXEC; - if (service->isValid()) - requestResult.error = i18n("Service '%1' must be executable to run.", service->entryPath()); - else - requestResult.error = i18n("Service '%1' is malformatted.", service->entryPath()); - cancel_service_startup_info( NULL, startup_id, envs ); // cancel it if any - return false; - } - KLaunchRequest *request = new KLaunchRequest; - request->autoStart = autoStart; - - if ((urls.count() > 1) && !service->allowMultipleFiles()) - { - // We need to launch the application N times. That sucks. - // We ignore the result for application 2 to N. - // For the first file we launch the application in the - // usual way. The reported result is based on this - // application. - foreach(const QString &it, urls) { - QByteArray startup_id2 = startup_id; - const QStringList singleUrl(it); - if( !startup_id2.isEmpty() && startup_id2 != "0" ) - startup_id2 = "0"; // can't use the same startup_id several times // krazy:exclude=doublequote_chars - start_service( service, singleUrl, envs, startup_id2, true, false, msg); - } - QString firstURL = *(urls.begin()); - urls.clear(); - urls.append(firstURL); - } - createArgs(request, service, urls); - - // We must have one argument at least! - if (!request->arg_list.count()) - { - requestResult.result = ENOEXEC; - requestResult.error = i18n("Service '%1' is malformatted.", service->entryPath()); - delete request; - cancel_service_startup_info( NULL, startup_id, envs ); - return false; - } - - request->name = request->arg_list.takeFirst(); - - if (request->name.endsWith(QLatin1String("/kioexec"))) { - // Special case for kioexec; if createArgs said we were going to use it, - // then we have to expect a kioexec-PID, not a org.kde.finalapp... - // Testcase: konqueror www.kde.org, RMB on link, open with, kruler. - - request->dbus_startup_type = KService::DBusMulti; - request->dbus_name = QString::fromLatin1("org.kde.kioexec"); - } else { - request->dbus_startup_type = service->dbusStartupType(); - - if ((request->dbus_startup_type == KService::DBusUnique) || - (request->dbus_startup_type == KService::DBusMulti)) { - const QVariant v = service->property(QLatin1String("X-DBUS-ServiceName")); - if (v.isValid()) { - request->dbus_name = v.toString(); - } - if (request->dbus_name.isEmpty()) { - const QString binName = KRun::binaryName(service->exec(), true); - request->dbus_name = QString::fromLatin1("org.kde.") + binName; - request->tolerant_dbus_name = QString::fromLatin1("*.") + binName; - } - } - } - -#ifdef KLAUNCHER_VERBOSE_OUTPUT - kDebug(7016) << "name=" << request->name << "dbus_name=" << request->dbus_name - << "startup type=" << s_DBusStartupTypeToString[request->dbus_startup_type]; -#endif - - request->pid = 0; - request->envs = envs; - send_service_startup_info( request, service, startup_id, envs ); - - // Request will be handled later. - if (!blind && !autoStart) - { - msg.setDelayedReply(true); - request->transaction = msg; - } - queueRequest(request); - return true; -} - -void -KLauncher::send_service_startup_info( KLaunchRequest *request, KService::Ptr service, const QByteArray& startup_id, - const QStringList &envs ) -{ -#ifdef Q_WS_X11 - request->startup_id = "0";// krazy:exclude=doublequote_chars - if (startup_id == "0") - return; - bool silent; - QByteArray wmclass; - if( !KRun::checkStartupNotify( QString(), service.data(), &silent, &wmclass )) - return; - KStartupInfoId id; - id.initId(startup_id); - QByteArray dpy_str; - foreach (const QString &env, envs) { - if (env.startsWith(QLatin1String("DISPLAY="))) - dpy_str = env.mid(8).toLocal8Bit(); - } - Display* dpy = NULL; - if (!dpy_str.isEmpty() && mCached_dpy != NULL && dpy_str != XDisplayString(mCached_dpy)) - dpy = mCached_dpy; - if (dpy == NULL) - dpy = XOpenDisplay(dpy_str); - request->startup_id = id.id(); - if (dpy == NULL) { - cancel_service_startup_info( request, startup_id, envs ); - return; - } - - request->startup_dpy = dpy_str; - - KStartupInfoData data; - data.setName( service->name()); - data.setIcon( service->icon()); - data.setDescription( i18n( "Launching %1" , service->name())); - if( !wmclass.isEmpty()) - data.setWMClass( wmclass ); - if( silent ) - data.setSilent( KStartupInfoData::Yes ); - data.setApplicationId( service->entryPath()); - // the rest will be sent by kdeinit - KStartupInfo::sendStartupX( dpy, id, data ); - if( mCached_dpy != dpy && mCached_dpy != NULL ) - XCloseDisplay( mCached_dpy ); - mCached_dpy = dpy; - return; -#else - return; -#endif -} - -void -KLauncher::cancel_service_startup_info( KLaunchRequest* request, const QByteArray& startup_id, - const QStringList &envs ) -{ -#ifdef Q_WS_X11 - if( request != NULL ) - request->startup_id = "0"; // krazy:exclude=doublequote_chars - if( !startup_id.isEmpty() && startup_id != "0" ) - { - QByteArray dpy_bytes; - foreach (const QString &env, envs) { - if (env.startsWith(QLatin1String("DISPLAY="))) - dpy_bytes = env.mid(8).toLatin1(); - } - Display* dpy = NULL; - if( !dpy_bytes.isEmpty() && mCached_dpy != NULL - && dpy_bytes != XDisplayString( mCached_dpy ) ) - dpy = mCached_dpy; - if( dpy == NULL ) - dpy = XOpenDisplay( dpy_bytes.constData() ); - if( dpy == NULL ) - return; - KStartupInfoId id; - id.initId(startup_id); - KStartupInfo::sendFinishX( dpy, id ); - if( mCached_dpy != dpy && mCached_dpy != NULL ) - XCloseDisplay( mCached_dpy ); - mCached_dpy = dpy; - } -#endif -} - -bool -KLauncher::kdeinit_exec(const QString &app, const QStringList &args, - const QString& workdir, const QStringList &envs, - const QString &startup_id, bool wait, QDBusMessage msg) -{ - KLaunchRequest *request = new KLaunchRequest; - request->autoStart = false; - request->arg_list = args; - request->name = app; - if (wait) - request->dbus_startup_type = KService::DBusWait; - else - request->dbus_startup_type = KService::DBusNone; - request->pid = 0; -#ifdef Q_WS_X11 - request->startup_id = startup_id.toLocal8Bit(); -#endif - request->envs = envs; - request->cwd = workdir; -#ifdef Q_WS_X11 - if (!app.endsWith(QLatin1String("kbuildsycoca4"))) { // avoid stupid loop - // Find service, if any - strip path if needed - const QString desktopName = app.mid(app.lastIndexOf(QLatin1Char('/')) + 1); - KService::Ptr service = KService::serviceByDesktopName(desktopName); - if (service) - send_service_startup_info(request, service, - request->startup_id, envs); - else // no .desktop file, no startup info - cancel_service_startup_info(request, request->startup_id, envs); - } -#endif - msg.setDelayedReply(true); - request->transaction = msg; - queueRequest(request); - return true; -} - -void -KLauncher::queueRequest(KLaunchRequest *request) -{ - requestQueue.append( request ); - if (!bProcessingQueue) - { - bProcessingQueue = true; - QTimer::singleShot(0, this, SLOT(slotDequeue())); - } -} - -void -KLauncher::slotDequeue() -{ - do { - KLaunchRequest *request = requestQueue.takeFirst(); - // process request - request->status = KLaunchRequest::Launching; - requestStart(request); - if (request->status != KLaunchRequest::Launching) - { - // Request handled. -#ifdef KLAUNCHER_VERBOSE_OUTPUT - kDebug(7016) << "Request handled already"; -#endif - requestDone( request ); - continue; - } - } while(requestQueue.count()); - bProcessingQueue = false; -} - -void -KLauncher::createArgs( KLaunchRequest *request, const KService::Ptr service , - const QStringList &urls) -{ - const QStringList params = KRun::processDesktopExec(*service, urls); - - for(QStringList::ConstIterator it = params.begin(); - it != params.end(); ++it) - { - request->arg_list.append(*it); - } - - const QString& path = service->path(); - if (!path.isEmpty()) { - request->cwd = path; - } else if (!urls.isEmpty()) { - const KUrl url(urls.first()); - if (url.isLocalFile()) { - request->cwd = url.directory(); - } - } -} - -///// IO-Slave functions - -pid_t -KLauncher::requestHoldSlave(const KUrl &url, const QString &app_socket) -{ - IdleSlave *slave = 0; - foreach (IdleSlave *p, mSlaveList) - { - if (p->onHold(url)) - { - slave = p; - break; - } - } - if (slave) - { - mSlaveList.removeAll(slave); - slave->connect(app_socket); - return slave->pid(); - } - return 0; -} - -pid_t -KLauncher::requestSlave(const QString &protocol, - const QString &host, - const QString &app_socket, - QString &error) -{ - IdleSlave *slave = 0; - foreach (IdleSlave *p, mSlaveList) - { - if (p->match(protocol, host, true)) - { - slave = p; - break; - } - } - if (!slave) - { - foreach (IdleSlave *p, mSlaveList) - { - if (p->match(protocol, host, false)) - { - slave = p; - break; - } - } - } - if (!slave) - { - foreach (IdleSlave *p, mSlaveList) - { - if (p->match(protocol, QString(), false)) - { - slave = p; - break; - } - } - } - if (slave) - { - mSlaveList.removeAll(slave); - slave->connect(app_socket); - return slave->pid(); - } - - QString name = KProtocolInfo::exec(protocol); - if (name.isEmpty()) - { - error = i18n("Unknown protocol '%1'.\n", protocol); - return 0; - } - - QStringList arg_list; - arg_list.append(protocol); - arg_list.append(mConnectionServer.address()); - arg_list.append(app_socket); - - kDebug(7016) << "KLauncher: launching new slave " << name << " with protocol=" << protocol - << " args=" << arg_list; - -#ifdef Q_OS_UNIX - if (mSlaveDebug == protocol) - { - klauncher_header request_header; - request_header.cmd = LAUNCHER_DEBUG_WAIT; - request_header.arg_length = 0; - kde_safe_write(kdeinitSocket, &request_header, sizeof(request_header)); - } - if (mSlaveValgrind == protocol) { - KPluginLoader lib(name, KGlobal::mainComponent()); - arg_list.prepend(lib.fileName()); - arg_list.prepend(KStandardDirs::findExe(QString::fromLatin1("kioslave"))); - name = QString::fromLatin1("valgrind"); - - if (!mSlaveValgrindSkin.isEmpty()) { - arg_list.prepend(QLatin1String("--tool=") + mSlaveValgrindSkin); - } else { - arg_list.prepend(QLatin1String("--tool=memcheck")); - } - } -#endif - KLaunchRequest *request = new KLaunchRequest; - request->autoStart = false; - request->name = name; - request->arg_list = arg_list; - request->dbus_startup_type = KService::DBusNone; - request->pid = 0; -#ifdef Q_WS_X11 - request->startup_id = "0"; // krazy:exclude=doublequote_chars -#endif - request->status = KLaunchRequest::Launching; - requestStart(request); - pid_t pid = request->pid; - -// kDebug(7016) << "Slave launched, pid = " << pid; - - // We don't care about this request any longer.... - requestDone(request); - if (!pid) - { - error = i18n("Error loading '%1'.\n", name); - } - return pid; -} - -bool KLauncher::checkForHeldSlave(const QString &url) -{ - Q_FOREACH (const IdleSlave *p, mSlaveList) { - if (p->onHold(url)) { - return true; - } - } - return false; -} - -void -KLauncher::waitForSlave(pid_t pid, QDBusMessage msg) -{ - foreach (const IdleSlave *slave, mSlaveList) - { - if (slave->pid() == pid) - return; // Already here. - } - SlaveWaitRequest *waitRequest = new SlaveWaitRequest; - msg.setDelayedReply(true); - waitRequest->transaction = msg; - waitRequest->pid = pid; - mSlaveWaitRequest.append(waitRequest); -} - -void -KLauncher::acceptSlave() -{ - IdleSlave *slave = new IdleSlave(this); - mConnectionServer.setNextPendingConnection(&slave->mConn); - mSlaveList.append(slave); - connect(slave, SIGNAL(destroyed()), this, SLOT(slotSlaveGone())); - connect(slave, SIGNAL(statusUpdate(IdleSlave*)), - this, SLOT(slotSlaveStatus(IdleSlave*))); - if (!mTimer.isActive()) - { - mTimer.start(1000*10); + const int equalindex = sessionmanager.indexOf('='); + kDebug() << "SESSION_MANAGER" << sessionmanager; + if (equalindex > 0) { + const QByteArray sessionmanagervalue = sessionmanager.mid(equalindex + 1, sessionmanager.size() - equalindex - 1); + kDebug() << "SESSION_MANAGER" << sessionmanager << sessionmanagervalue; + m_adaptor->setLaunchEnv(QString::fromLatin1("SESSION_MANAGER"), sessionmanagervalue); } } -void -KLauncher::slotSlaveStatus(IdleSlave *slave) +int main(int argc, char *argv[]) { - QMutableListIterator it(mSlaveWaitRequest); - while(it.hasNext()) - { - SlaveWaitRequest *waitRequest = it.next(); - if (waitRequest->pid == slave->pid()) - { - QDBusConnection::sessionBus().send(waitRequest->transaction.createReply()); - it.remove(); - delete waitRequest; - } + KAboutData aboutData( + "klauncher", "kdelibs4", ki18n("KDE launcher"), + KDE_VERSION_STRING, + ki18n("KDE launcher - launches and autostarts applications") + ); + + KCmdLineArgs::init(argc, argv, &aboutData); + + const QByteArray sessionmanager = qgetenv("SESSION_MANAGER"); + + // NOTE: disables session manager entirely, for reference: + // https://www.x.org/releases/X11R7.7/doc/libSM/xsmp.html + ::unsetenv("SESSION_MANAGER"); + + KApplication app; + app.setQuitOnLastWindowClosed(false); + app.disableSessionManagement(); + app.quitOnSignal(); + + QDBusConnection session = QDBusConnection::sessionBus(); + if (!session.isConnected()) { + kWarning() << "No DBUS session-bus found. Check if you have started the DBUS server."; + return 1; } -} - -void -KLauncher::slotSlaveGone() -{ - IdleSlave *slave = (IdleSlave *) sender(); - mSlaveList.removeAll(slave); - if ((mSlaveList.count() == 0) && (mTimer.isActive())) - { - mTimer.stop(); + QDBusReply sessionReply = session.interface()->isServiceRegistered("org.kde.klauncher"); + if (sessionReply.isValid() && sessionReply.value() == true) { + kWarning() << "Another instance of klauncher is already running!"; + return 2; } -} -void -KLauncher::idleTimeout() -{ - const time_t now = time(0); - foreach (IdleSlave *slave, mSlaveList) - { - if (slave->age(now) > SLAVE_MAX_IDLE) - { - // killing idle slave - delete slave; - } - } -} + KLauncher klauncher(&app); + klauncher.setSessionManager(sessionmanager); -void KLauncher::reparseConfiguration() -{ - KProtocolManager::reparseConfiguration(); - foreach (IdleSlave *slave, mSlaveList) - slave->reparseConfiguration(); -} - -void KLauncher::terminate_kdeinit() -{ - kDebug(7016); - klauncher_header request_header; - request_header.cmd = LAUNCHER_TERMINATE_KDEINIT; - request_header.arg_length = 0; - kde_safe_write(kdeinitSocket, &request_header, sizeof(request_header)); + return app.exec(); // keep running } #include "moc_klauncher.cpp" diff --git a/kinit/klauncher.h b/kinit/klauncher.h index 270ce2bf..2299d11a 100644 --- a/kinit/klauncher.h +++ b/kinit/klauncher.h @@ -1,251 +1,39 @@ -/* - This file is part of the KDE libraries - Copyright (c) 1999 Waldo Bastian +/* This file is part of the KDE libraries + Copyright (C) 2022 Ivailo Monev - 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 -#include -#include - -#ifdef Q_WS_X11 -#include -#include -#endif - -#include -#include -#include -#include - -#include -#include -#include - -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 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 requestList; // Requests being handled - QList requestQueue; // Requests waiting to being handled - KLaunchRequest *lastRequest; - QList mSlaveWaitRequest; - int kdeinitSocket; - QSocketNotifier *kdeinitNotifier; - KIO::ConnectionServer mConnectionServer; - QList 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 diff --git a/kinit/klauncher_adaptor.cpp b/kinit/klauncher_adaptor.cpp index 9517d8eb..3a4dc070 100644 --- a/kinit/klauncher_adaptor.cpp +++ b/kinit/klauncher_adaptor.cpp @@ -1,141 +1,351 @@ -/* - * Copyright 2006, 2007 Thiago Macieira - * Copyright 2006-2008 David Faure - * - * 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 . - * - */ +/* This file is part of the KDE libraries + Copyright (C) 2022 Ivailo Monev + + 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 +#include +#include +#include +#include +#include +#include + +#include +#include + +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(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(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(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(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(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(parent())->reparseConfiguration(); -} - -qint64 KLauncherAdaptor::requestHoldSlave(const QString &url, const QString &app_socket) -{ - // handle method call org.kde.KLauncher.requestHoldSlave - return static_cast(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(parent())->requestSlave(protocol, host, app_socket, error); -} - -bool KLauncherAdaptor::checkForHeldSlave (const QString &url) -{ - return static_cast(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(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(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(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 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(parent())->waitForSlave(pid, msg); + QProcess* process = qobject_cast(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(parent()); - p->terminate_kdeinit(); + QProcess* process = qobject_cast(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" diff --git a/kinit/klauncher_adaptor.h b/kinit/klauncher_adaptor.h index dc4e91f9..b12e0808 100644 --- a/kinit/klauncher_adaptor.h +++ b/kinit/klauncher_adaptor.h @@ -1,47 +1,47 @@ -/* - * Copyright 2006, 2007 Thiago Macieira - * Copyright 2006-2008 David Faure - * - * 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 . - * - */ +/* This file is part of the KDE libraries + Copyright (C) 2022 Ivailo Monev -#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 -#include -#include + 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 -#include -#include -#include + 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 +#include +#include + +// 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 m_processes; + QStringList m_autostart; }; -#endif +#endif // KLAUNCHER_ADAPTOR_H diff --git a/kinit/klauncher_cmds.cpp b/kinit/klauncher_cmds.cpp deleted file mode 100644 index d9b74f8e..00000000 --- a/kinit/klauncher_cmds.cpp +++ /dev/null @@ -1,45 +0,0 @@ -/* - * Copyright 2009 David Faure - * - * 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"; - } -} diff --git a/kinit/klauncher_cmds.h b/kinit/klauncher_cmds.h deleted file mode 100644 index c2dc6aa4..00000000 --- a/kinit/klauncher_cmds.h +++ /dev/null @@ -1,127 +0,0 @@ -/* - This file is part of the KDE libraries - Copyright (c) 1999 Waldo Bastian - - 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 diff --git a/kinit/klauncher_main.cpp b/kinit/klauncher_main.cpp deleted file mode 100644 index a2a3f600..00000000 --- a/kinit/klauncher_main.cpp +++ /dev/null @@ -1,118 +0,0 @@ -/* - This file is part of the KDE libraries - Copyright (c) 1999 Waldo Bastian - - 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 - -#include -#include - -#include "klauncher.h" -#include -#include "kcrash.h" -#include "kdebug.h" -#include -#include -#include -#include -#include - -#include "klauncher_cmds.h" -#include - -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 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(); -} diff --git a/kinit/org.kde.klauncher.service.in b/kinit/org.kde.klauncher.service.in new file mode 100644 index 00000000..9e2f23a7 --- /dev/null +++ b/kinit/org.kde.klauncher.service.in @@ -0,0 +1,3 @@ +[D-BUS Service] +Name=org.kde.klauncher +Exec=@KDE4_BIN_INSTALL_DIR@/klauncher4 diff --git a/kinit/proctitle.cpp b/kinit/proctitle.cpp deleted file mode 100644 index bd34feba..00000000 --- a/kinit/proctitle.cpp +++ /dev/null @@ -1,89 +0,0 @@ -/* - * ProFTPD - FTP server daemon - * Copyright (c) 2007 The ProFTPD Project team //krazy:exclude=copyright - * Copyright (c) 2007 Alex Merry - * - * 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 -#include -#include -#include - -#ifdef HAVE_SETPROCTITLE -# define PF_ARGV_TYPE PF_ARGV_NONE -# include -# include -#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); -} diff --git a/kinit/proctitle.h b/kinit/proctitle.h deleted file mode 100644 index bcb63f8e..00000000 --- a/kinit/proctitle.h +++ /dev/null @@ -1,47 +0,0 @@ -/* - * ProFTPD - FTP server daemon - * Copyright (c) 2007 The ProFTPD Project team //krazy:exclude=copyright - * Copyright (c) 2007 Alex Merry - * - * 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 */ diff --git a/kio/kio/slave.cpp b/kio/kio/slave.cpp index a144b368..86cce3a3 100644 --- a/kio/kio/slave.cpp +++ b/kio/kio/slave.cpp @@ -38,7 +38,6 @@ #include #include #include -#include #include "kservice.h" #include @@ -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 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 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 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" diff --git a/kio/tests/krununittest.cpp b/kio/tests/krununittest.cpp index 44a1f764..e7eaff99 100644 --- a/kio/tests/krununittest.cpp +++ b/kio/tests/krununittest.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");