File indexing completed on 2024-04-14 14:23:51

0001 /*
0002     This file is part of the KDE libraries
0003     SPDX-FileCopyrightText: 1999 Waldo Bastian <bastian@kde.org>
0004 
0005     SPDX-License-Identifier: LGPL-2.0-only
0006 */
0007 
0008 #include <config-kdeinit.h>
0009 
0010 #include <klauncher_debug.h>
0011 
0012 #include <qplatformdefs.h>
0013 
0014 #include "klauncher.h"
0015 #include <KCrash>
0016 #include <stdio.h>
0017 #include <stdlib.h>
0018 #include <signal.h>
0019 #include <KLocalizedString>
0020 
0021 #include "klauncher_cmds.h"
0022 #include <QGuiApplication>
0023 #include <QFile>
0024 #include <QDebug>
0025 #include <QDBusConnectionInterface>
0026 #include <QThread>
0027 
0028 #ifdef Q_OS_OSX
0029 #include <CoreFoundation/CoreFoundation.h>
0030 #endif
0031 
0032 #ifndef USE_KPROCESS_FOR_KIOSLAVES
0033 static int sigpipe[ 2 ];
0034 static void sig_handler(int sig_num)
0035 {
0036     // No recursion
0037     signal(SIGHUP, SIG_IGN);
0038     signal(SIGTERM, SIG_IGN);
0039     fprintf(stderr, "klauncher: Exiting on signal %d\n", sig_num);
0040     char tmp = 'x';
0041     write(sigpipe[ 1 ], &tmp, 1);
0042 }
0043 #endif
0044 
0045 #if defined(Q_OS_DARWIN)
0046 // Copied from kkernel_mac.cpp
0047 bool dbus_initialized = false;
0048 
0049 /**
0050  Set the D-Bus environment based on session bus socket
0051 */
0052 
0053 bool mac_set_dbus_address(QString value)
0054 {
0055     if (!value.isEmpty() && QFile::exists(value) && (QFile::permissions(value) & QFile::WriteUser)) {
0056         value = QLatin1String("unix:path=") + value;
0057         qputenv("DBUS_SESSION_BUS_ADDRESS", value.toLocal8Bit());
0058         // qDebug() << "set session bus address to" << value;
0059         return true;
0060     }
0061     return false;
0062 }
0063 
0064 /**
0065  Make sure D-Bus is initialized, by any means necessary.
0066 */
0067 
0068 void mac_initialize_dbus()
0069 {
0070     enum
0071     {
0072         timeout = 3000 // msec. Copied from old kdecore/kernel/kkernel_mac.cpp
0073     };
0074 
0075     if (dbus_initialized) {
0076         return;
0077     }
0078 
0079     QString dbusVar = QString::fromLocal8Bit(qgetenv("DBUS_SESSION_BUS_ADDRESS"));
0080     if (!dbusVar.isEmpty()) {
0081         dbus_initialized = true;
0082         return;
0083     }
0084 
0085     dbusVar = QFile::decodeName(qgetenv("DBUS_LAUNCHD_SESSION_BUS_SOCKET"));
0086     if (mac_set_dbus_address(dbusVar)) {
0087         dbus_initialized = true;
0088         return;
0089     }
0090 
0091     QString externalProc;
0092     QStringList path = QFile::decodeName(qgetenv("KDEDIRS")).split(QLatin1Char(':')).replaceInStrings(QRegExp(QLatin1String("$")), QLatin1String("/bin"));
0093     path << QFile::decodeName(qgetenv("PATH")).split(QLatin1Char(':')) << QLatin1String("/usr/local/bin");
0094 
0095     for (int i = 0; i < path.size(); ++i) {
0096         QString testLaunchctl = QString(path.at(i)).append(QLatin1String("/launchctl"));
0097         if (QFile(testLaunchctl).exists()) {
0098             externalProc = testLaunchctl;
0099             break;
0100         }
0101     }
0102 
0103     if (!externalProc.isEmpty()) {
0104         QProcess qp;
0105         qp.setTextModeEnabled(true);
0106 
0107         qp.start(externalProc, QStringList() << QLatin1String("getenv") << QLatin1String("DBUS_LAUNCHD_SESSION_BUS_SOCKET"));
0108         if (!qp.waitForFinished(timeout)) {
0109             // qDebug() << "error running" << externalProc << qp.errorString();
0110             return;
0111         }
0112         if (qp.exitCode() != 0) {
0113             // qDebug() << externalProc << "unsuccessful:" << qp.readAllStandardError();
0114             return;
0115         }
0116 
0117         QString line = QString::fromLatin1(qp.readLine()).trimmed(); // read the first line
0118         if (mac_set_dbus_address(line)) {
0119             dbus_initialized = true;    // hooray
0120         }
0121     }
0122 
0123     if (dbus_initialized == false) {
0124         // qDebug() << "warning: unable to initialize D-Bus environment!";
0125     }
0126 
0127 }
0128 #endif
0129 
0130 extern "C" Q_DECL_EXPORT int kdemain(int argc, char **argv)
0131 {
0132 #ifndef Q_OS_WIN
0133     // Started via kdeinit.
0134     int launcherFd;
0135     if (argc != 2 || memcmp(argv[1], "--fd=", 5) || !(launcherFd = atoi(argv[1] + 5))) {
0136         fprintf(stderr, "%s", i18n("klauncher: This program is not supposed to be started manually.\n"
0137                                    "klauncher: It is started automatically by kdeinit5.\n").toLocal8Bit().data());
0138         return 1;
0139     }
0140 #endif
0141 
0142 #if defined(Q_OS_DARWIN)
0143     CFBundleRef mainBundle = CFBundleGetMainBundle();
0144     if (mainBundle) {
0145         // get the application's Info Dictionary. For app bundles this would live in the bundle's Info.plist,
0146         // for regular executables it is obtained in another way.
0147         CFMutableDictionaryRef infoDict = (CFMutableDictionaryRef) CFBundleGetInfoDictionary(mainBundle);
0148         if (infoDict) {
0149             // Add or set the "LSUIElement" key with/to value "1". This can simply be a CFString.
0150             CFDictionarySetValue(infoDict, CFSTR("LSUIElement"), CFSTR("1"));
0151             // That's it. We're now considered as an "agent" by the window server, and thus will have
0152             // neither menubar nor presence in the Dock or App Switcher.
0153         }
0154     }
0155     mac_initialize_dbus();
0156 #endif
0157 
0158     // WABA: Make sure not to enable session management.
0159     qunsetenv("SESSION_MANAGER");
0160 
0161     // Disable the GLib event loop (rh#983110)
0162     const bool wasQtNoGlibSet = !qEnvironmentVariableIsEmpty("QT_NO_GLIB");
0163     if (!wasQtNoGlibSet) {
0164        qputenv("QT_NO_GLIB", "1");
0165     }
0166 
0167     // We need a QGuiApplication as we use X11
0168     QGuiApplication app(argc, argv);
0169     app.setApplicationName(QStringLiteral("klauncher"));
0170 
0171     // Now get rid of QT_NO_GLIB again so launched processes don't inherit it
0172     if (!wasQtNoGlibSet) {
0173        qunsetenv("QT_NO_GLIB");
0174     }
0175 
0176     int maxTry = 3;
0177     while (true) {
0178         QString service(QStringLiteral("org.kde.klauncher5")); // same as ktoolinvocation.cpp
0179         if (!QDBusConnection::sessionBus().isConnected()) {
0180             qCWarning(KLAUNCHER) << "No D-Bus session-bus found. Check if you have started the D-Bus server.";
0181             return 1;
0182         }
0183         QDBusReply<QDBusConnectionInterface::RegisterServiceReply> reply =
0184             QDBusConnection::sessionBus().interface()->registerService(service);
0185         if (!reply.isValid()) {
0186             qCWarning(KLAUNCHER) << "D-Bus communication problem!";
0187             return 1;
0188         }
0189         if (reply == QDBusConnectionInterface::ServiceRegistered) {
0190             break;
0191         }
0192 
0193         if (--maxTry == 0) {
0194             qCWarning(KLAUNCHER) << "Another instance of klauncher is already running!";
0195             return 1;
0196         }
0197 
0198         // Wait a bit...
0199         qCWarning(KLAUNCHER) << "Waiting for already running klauncher to exit.";
0200         QThread::sleep(1);
0201 
0202         // Try again...
0203     }
0204 
0205 #ifndef USE_KPROCESS_FOR_KIOSLAVES
0206     KLauncher *launcher = new KLauncher(launcherFd);
0207 #else
0208     KLauncher *launcher = new KLauncher();
0209 #endif
0210     QDBusConnection::sessionBus().registerObject(QStringLiteral("/"), launcher);
0211 
0212 #ifndef USE_KPROCESS_FOR_KIOSLAVES
0213     if (pipe(sigpipe) != 0) {
0214         perror("klauncher: pipe failed.");
0215         return 1;
0216     }
0217     QSocketNotifier *signotif = new QSocketNotifier(sigpipe[ 0 ], QSocketNotifier::Read, launcher);
0218     QObject::connect(signotif, SIGNAL(activated(int)), launcher, SLOT(destruct()));
0219     KCrash::setEmergencySaveFunction(sig_handler);
0220     signal(SIGHUP, sig_handler);
0221     signal(SIGPIPE, SIG_IGN);
0222     signal(SIGTERM, sig_handler);
0223 #endif
0224 
0225     return app.exec();
0226 }