File indexing completed on 2024-05-12 03:56:42

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 *_kioworker_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: kioworker <worker-lib> <protocol> <klauncher-socket> <app-socket>\n\nThis program is part of KDE.\n");
0045         return 1;
0046     }
0047 
0048     setlocale(LC_ALL, "");
0049     QString libname = QFile::decodeName(argv[1]);
0050 
0051     if (libname.isEmpty()) {
0052         fprintf(stderr, "library path is empty.\n");
0053         return 1;
0054     }
0055 
0056     // Use QPluginLoader to locate the library when using a relative path
0057     // But we need to use QLibrary to actually load it, because of resolve()!
0058     QString libpath = QPluginLoader(libname).fileName();
0059     if (libpath.isEmpty()) {
0060         fprintf(stderr, "could not locate %s, check QT_PLUGIN_PATH\n", qPrintable(libname));
0061         return 1;
0062     }
0063 
0064     QLibrary lib(libpath);
0065     if (!lib.load()) {
0066         fprintf(stderr, "could not open %s: %s\n", qPrintable(libname), qPrintable(lib.errorString()));
0067         return 1;
0068     }
0069 
0070     QFunctionPointer sym = lib.resolve("kdemain");
0071     if (!sym) {
0072         fprintf(stderr, "Could not find kdemain: %s\n", qPrintable(lib.errorString()));
0073         return 1;
0074     }
0075 
0076     const QByteArray workerDebugWait = qgetenv("KIOWORKER_DEBUG_WAIT");
0077 
0078 #ifdef Q_OS_WIN
0079     // enter debugger in case debugging is activated
0080     if (workerDebugWait == "all" || workerDebugWait == argv[2]) {
0081 #ifdef Q_CC_MSVC
0082         // msvc debugger or windbg supports jit debugging, the latter requires setting up windbg jit with windbg -i
0083         DebugBreak();
0084 #else
0085         // gdb does not support win32 jit debug support, so implement it by ourself
0086         WCHAR buf[1024];
0087         GetModuleFileName(NULL, buf, 1024);
0088         QStringList params;
0089         params << QString::fromUtf16(reinterpret_cast<const char16_t *>(buf));
0090         params << QString::number(GetCurrentProcessId());
0091         const QString gdbExec = QStandardPaths::findExecutable(QStringLiteral("gdb"));
0092         if (gdbExec.isEmpty()) {
0093             fprintf(stderr, "Could not find 'gdb' executable in PATH\n");
0094             return 1;
0095         }
0096         QProcess::startDetached(gdbExec, params);
0097         Sleep(1000);
0098 #endif
0099     }
0100 #if defined(Q_CC_MSVC)
0101     else {
0102         QString workerDebugPopup(QString::fromLocal8Bit(qgetenv("KIOWORKER_DEBUG_POPUP")));
0103         if (workerDebugPopup == QLatin1String("all") || workerDebugPopup == QString::fromLocal8Bit(argv[2])) {
0104             // A workaround for OSes where DebugBreak() does not work in administrative mode (actually Vista with msvc 2k5)
0105             // - display a native message box so developer can attach the debugger to the KIO worker process and click OK.
0106             MessageBoxA(
0107                 NULL,
0108                 QStringLiteral("Please attach the debugger to process #%1 (%2)").arg(getpid()).arg(QString::fromLocal8Bit(argv[0])).toLatin1().constData(),
0109                 QStringLiteral("\"%1\" KIO Worker Debugging").arg(QString::fromLocal8Bit(argv[2])).toLatin1().constData(),
0110                 MB_OK | MB_ICONINFORMATION | MB_TASKMODAL);
0111         }
0112     }
0113 #endif
0114 #endif // Q_OS_WIN
0115 
0116 #if defined(Q_OS_UNIX)
0117     // Enter debugger in case debugging is activated
0118     if (workerDebugWait == "all" || workerDebugWait == argv[2]) {
0119         const pid_t pid = getpid();
0120         fprintf(stderr,
0121                 "kioworker: Suspending process to debug io worker(s): %s\n"
0122                 "kioworker: 'gdb kioworker %d' to debug\n"
0123                 "kioworker: 'kill -SIGCONT %d' to continue\n",
0124                 workerDebugWait.constData(),
0125                 pid,
0126                 pid);
0127 
0128         kill(pid, SIGSTOP);
0129     }
0130 #endif
0131 
0132     int (*func)(int, char *[]) = (int (*)(int, char *[]))sym;
0133 
0134     // We need argv[0] to remain /path/to/kioworker
0135     // so that applicationDirPath() is correct on non-Linux (no /proc)
0136     // and we want to skip argv[1] so the kioworker exe is transparent to kdemain.
0137     const int newArgc = argc - 1;
0138     QVarLengthArray<char *, 5> newArgv(newArgc);
0139     newArgv[0] = argv[0];
0140     for (int i = 1; i < newArgc; ++i) {
0141         newArgv[i] = argv[i + 1];
0142     }
0143 
0144     return func(newArgc, newArgv.data()); /* Launch! */
0145 }