File indexing completed on 2024-04-28 15:27:02

0001 /*
0002     This file is part of the KDE libraries
0003     SPDX-FileCopyrightText: 1999-2000 Waldo Bastian <bastian@kde.org>
0004     SPDX-FileCopyrightText: 1999 Mario Weilguni <mweilguni@sime.com>
0005     SPDX-FileCopyrightText: 2001 Lubos Lunak <l.lunak@kde.org>
0006 
0007     SPDX-License-Identifier: LGPL-2.0-only
0008 */
0009 
0010 #include <cerrno>
0011 #include <locale.h>
0012 #include <signal.h>
0013 #include <stdio.h>
0014 #include <stdlib.h>
0015 
0016 #include <QFile>
0017 #include <QLibrary>
0018 #include <QPluginLoader>
0019 #include <QString>
0020 
0021 #ifdef Q_OS_WIN
0022 #include <QProcess>
0023 #include <QStandardPaths>
0024 #include <QStringList>
0025 
0026 #include <process.h>
0027 #include <qt_windows.h>
0028 #endif
0029 
0030 #ifndef Q_OS_WIN
0031 #include <unistd.h>
0032 
0033 /* These are to link libkio even if 'smart' linker is used */
0034 #include <kio/authinfo.h>
0035 extern "C" KIO::AuthInfo *_kioslave_init_kio()
0036 {
0037     return new KIO::AuthInfo();
0038 }
0039 #endif
0040 
0041 int main(int argc, char **argv)
0042 {
0043     if (argc < 5) {
0044         fprintf(stderr, "Usage: kioslave5 <slave-lib> <protocol> <klauncher-socket> <app-socket>\n\nThis program is part of KDE.\n");
0045         return 1;
0046     }
0047 #ifndef _WIN32_WCE
0048     setlocale(LC_ALL, "");
0049 #endif
0050     QString libname = QFile::decodeName(argv[1]);
0051 
0052     if (libname.isEmpty()) {
0053         fprintf(stderr, "library path is empty.\n");
0054         return 1;
0055     }
0056 
0057     // Use QPluginLoader to locate the library when using a relative path
0058     // But we need to use QLibrary to actually load it, because of resolve()!
0059     QString libpath = QPluginLoader(libname).fileName();
0060     if (libpath.isEmpty()) {
0061         fprintf(stderr, "could not locate %s, check QT_PLUGIN_PATH\n", qPrintable(libname));
0062         return 1;
0063     }
0064 
0065     QLibrary lib(libpath);
0066     if (!lib.load()) {
0067         fprintf(stderr, "could not open %s: %s\n", qPrintable(libname), qPrintable(lib.errorString()));
0068         return 1;
0069     }
0070 
0071     QFunctionPointer sym = lib.resolve("kdemain");
0072     if (!sym) {
0073         fprintf(stderr, "Could not find kdemain: %s\n", qPrintable(lib.errorString()));
0074         return 1;
0075     }
0076 
0077     const QByteArray slaveDebugWait = qgetenv("KDE_SLAVE_DEBUG_WAIT");
0078 
0079 #ifdef Q_OS_WIN
0080     // enter debugger in case debugging is activated
0081     if (slaveDebugWait == "all" || slaveDebugWait == argv[2]) {
0082 #ifdef Q_CC_MSVC
0083         // msvc debugger or windbg supports jit debugging, the latter requires setting up windbg jit with windbg -i
0084         DebugBreak();
0085 #else
0086         // gdb does not support win32 jit debug support, so implement it by ourself
0087         WCHAR buf[1024];
0088         GetModuleFileName(NULL, buf, 1024);
0089         QStringList params;
0090         params << QString::fromUtf16((const unsigned short *)buf);
0091         params << QString::number(GetCurrentProcessId());
0092         const QString gdbExec = QStandardPaths::findExecutable(QStringLiteral("gdb"));
0093         if (gdbExec.isEmpty()) {
0094             fprintf(stderr, "Could not find 'gdb' executable in PATH\n");
0095             return 1;
0096         }
0097         QProcess::startDetached(gdbExec, params);
0098         Sleep(1000);
0099 #endif
0100     }
0101 #if defined(Q_CC_MSVC) && !defined(_WIN32_WCE)
0102     else {
0103         QString slaveDebugPopup(QString::fromLocal8Bit(qgetenv("KDE_SLAVE_DEBUG_POPUP")));
0104         if (slaveDebugPopup == QLatin1String("all") || slaveDebugPopup == QString::fromLocal8Bit(argv[2])) {
0105             // A workaround for OSes where DebugBreak() does not work in administrative mode (actually Vista with msvc 2k5)
0106             // - display a native message box so developer can attach the debugger to the KIO slave process and click OK.
0107             MessageBoxA(
0108                 NULL,
0109                 QStringLiteral("Please attach the debugger to process #%1 (%2)").arg(getpid()).arg(QString::fromLocal8Bit(argv[0])).toLatin1().constData(),
0110                 QStringLiteral("\"%1\" KIO Slave Debugging").arg(QString::fromLocal8Bit(argv[2])).toLatin1().constData(),
0111                 MB_OK | MB_ICONINFORMATION | MB_TASKMODAL);
0112         }
0113     }
0114 #endif
0115 #endif // Q_OS_WIN
0116 
0117 #if defined(Q_OS_UNIX)
0118     // Enter debugger in case debugging is activated
0119     if (slaveDebugWait == "all" || slaveDebugWait == argv[2]) {
0120         const pid_t pid = getpid();
0121         fprintf(stderr,
0122                 "kioslave5: Suspending process to debug io slave(s): %s\n"
0123                 "kioslave5: 'gdb kioslave5 %d' to debug\n"
0124                 "kioslave5: 'kill -SIGCONT %d' to continue\n",
0125                 slaveDebugWait.constData(),
0126                 pid,
0127                 pid);
0128 
0129         kill(pid, SIGSTOP);
0130     }
0131 #endif
0132 
0133     int (*func)(int, char *[]) = (int (*)(int, char *[]))sym;
0134 
0135     // We need argv[0] to remain /path/to/kioslave5
0136     // so that applicationDirPath() is correct on non-Linux (no /proc)
0137     // and we want to skip argv[1] so the kioslave5 exe is transparent to kdemain.
0138     const int newArgc = argc - 1;
0139     QVarLengthArray<char *, 5> newArgv(newArgc);
0140     newArgv[0] = argv[0];
0141     for (int i = 1; i < newArgc; ++i) {
0142         newArgv[i] = argv[i + 1];
0143     }
0144 
0145     return func(newArgc, newArgv.data()); /* Launch! */
0146 }