| 1 | /* |
| 2 | This file is part of the KDE libraries |
| 3 | SPDX-FileCopyrightText: 1999-2000 Waldo Bastian <bastian@kde.org> |
| 4 | SPDX-FileCopyrightText: 1999 Mario Weilguni <mweilguni@sime.com> |
| 5 | SPDX-FileCopyrightText: 2001 Lubos Lunak <l.lunak@kde.org> |
| 6 | |
| 7 | SPDX-License-Identifier: LGPL-2.0-only |
| 8 | */ |
| 9 | |
| 10 | #include <cerrno> |
| 11 | #include <locale.h> |
| 12 | #include <signal.h> |
| 13 | #include <stdio.h> |
| 14 | #include <stdlib.h> |
| 15 | |
| 16 | #include <QFile> |
| 17 | #include <QLibrary> |
| 18 | #include <QPluginLoader> |
| 19 | #include <QString> |
| 20 | |
| 21 | #ifdef Q_OS_WIN |
| 22 | #include <QProcess> |
| 23 | #include <QStandardPaths> |
| 24 | #include <QStringList> |
| 25 | |
| 26 | #include <process.h> |
| 27 | #include <qt_windows.h> |
| 28 | #endif |
| 29 | |
| 30 | #ifndef Q_OS_WIN |
| 31 | #include <unistd.h> |
| 32 | |
| 33 | /* These are to link libkio even if 'smart' linker is used */ |
| 34 | #include <kio/authinfo.h> |
| 35 | extern "C" KIO::AuthInfo *_kioworker_init_kio() |
| 36 | { |
| 37 | return new KIO::AuthInfo(); |
| 38 | } |
| 39 | #endif |
| 40 | |
| 41 | int main(int argc, char **argv) |
| 42 | { |
| 43 | if (argc < 5) { |
| 44 | fprintf(stderr, format: "Usage: kioworker <worker-lib> <protocol> <klauncher-socket> <app-socket>\n\nThis program is part of KDE.\n" ); |
| 45 | return 1; |
| 46 | } |
| 47 | |
| 48 | setlocale(LC_ALL, locale: "" ); |
| 49 | QString libname = QFile::decodeName(localFileName: argv[1]); |
| 50 | |
| 51 | if (libname.isEmpty()) { |
| 52 | fprintf(stderr, format: "library path is empty.\n" ); |
| 53 | return 1; |
| 54 | } |
| 55 | |
| 56 | // Use QPluginLoader to locate the library when using a relative path |
| 57 | // But we need to use QLibrary to actually load it, because of resolve()! |
| 58 | QString libpath = QPluginLoader(libname).fileName(); |
| 59 | if (libpath.isEmpty()) { |
| 60 | fprintf(stderr, format: "could not locate %s, check QT_PLUGIN_PATH\n" , qPrintable(libname)); |
| 61 | return 1; |
| 62 | } |
| 63 | |
| 64 | QLibrary lib(libpath); |
| 65 | if (!lib.load()) { |
| 66 | fprintf(stderr, format: "could not open %s: %s\n" , qPrintable(libname), qPrintable(lib.errorString())); |
| 67 | return 1; |
| 68 | } |
| 69 | |
| 70 | QFunctionPointer sym = lib.resolve(symbol: "kdemain" ); |
| 71 | if (!sym) { |
| 72 | fprintf(stderr, format: "Could not find kdemain: %s\n" , qPrintable(lib.errorString())); |
| 73 | return 1; |
| 74 | } |
| 75 | |
| 76 | const QByteArray workerDebugWait = qgetenv(varName: "KIOWORKER_DEBUG_WAIT" ); |
| 77 | |
| 78 | #ifdef Q_OS_WIN |
| 79 | // enter debugger in case debugging is activated |
| 80 | if (workerDebugWait == "all" || workerDebugWait == argv[2]) { |
| 81 | #ifdef Q_CC_MSVC |
| 82 | // msvc debugger or windbg supports jit debugging, the latter requires setting up windbg jit with windbg -i |
| 83 | DebugBreak(); |
| 84 | #else |
| 85 | // gdb does not support win32 jit debug support, so implement it by ourself |
| 86 | WCHAR buf[1024]; |
| 87 | GetModuleFileName(NULL, buf, 1024); |
| 88 | QStringList params; |
| 89 | params << QString::fromUtf16(reinterpret_cast<const char16_t *>(buf)); |
| 90 | params << QString::number(GetCurrentProcessId()); |
| 91 | const QString gdbExec = QStandardPaths::findExecutable(QStringLiteral("gdb" )); |
| 92 | if (gdbExec.isEmpty()) { |
| 93 | fprintf(stderr, "Could not find 'gdb' executable in PATH\n" ); |
| 94 | return 1; |
| 95 | } |
| 96 | QProcess::startDetached(gdbExec, params); |
| 97 | Sleep(1000); |
| 98 | #endif |
| 99 | } |
| 100 | #if defined(Q_CC_MSVC) |
| 101 | else { |
| 102 | QString workerDebugPopup(QString::fromLocal8Bit(qgetenv("KIOWORKER_DEBUG_POPUP" ))); |
| 103 | if (workerDebugPopup == QLatin1String("all" ) || workerDebugPopup == QString::fromLocal8Bit(argv[2])) { |
| 104 | // A workaround for OSes where DebugBreak() does not work in administrative mode (actually Vista with msvc 2k5) |
| 105 | // - display a native message box so developer can attach the debugger to the KIO worker process and click OK. |
| 106 | MessageBoxA( |
| 107 | NULL, |
| 108 | QStringLiteral("Please attach the debugger to process #%1 (%2)" ).arg(getpid()).arg(QString::fromLocal8Bit(argv[0])).toLatin1().constData(), |
| 109 | QStringLiteral("\"%1\" KIO Worker Debugging" ).arg(QString::fromLocal8Bit(argv[2])).toLatin1().constData(), |
| 110 | MB_OK | MB_ICONINFORMATION | MB_TASKMODAL); |
| 111 | } |
| 112 | } |
| 113 | #endif |
| 114 | #endif // Q_OS_WIN |
| 115 | |
| 116 | #if defined(Q_OS_UNIX) |
| 117 | // Enter debugger in case debugging is activated |
| 118 | if (workerDebugWait == "all" || workerDebugWait == argv[2]) { |
| 119 | const pid_t pid = getpid(); |
| 120 | fprintf(stderr, |
| 121 | format: "kioworker: Suspending process to debug io worker(s): %s\n" |
| 122 | "kioworker: 'gdb kioworker %d' to debug\n" |
| 123 | "kioworker: 'kill -SIGCONT %d' to continue\n" , |
| 124 | workerDebugWait.constData(), |
| 125 | pid, |
| 126 | pid); |
| 127 | |
| 128 | kill(pid: pid, SIGSTOP); |
| 129 | } |
| 130 | #endif |
| 131 | |
| 132 | int (*func)(int, char *[]) = (int (*)(int, char *[]))sym; |
| 133 | |
| 134 | // We need argv[0] to remain /path/to/kioworker |
| 135 | // so that applicationDirPath() is correct on non-Linux (no /proc) |
| 136 | // and we want to skip argv[1] so the kioworker exe is transparent to kdemain. |
| 137 | const int newArgc = argc - 1; |
| 138 | QVarLengthArray<char *, 5> newArgv(newArgc); |
| 139 | newArgv[0] = argv[0]; |
| 140 | for (int i = 1; i < newArgc; ++i) { |
| 141 | newArgv[i] = argv[i + 1]; |
| 142 | } |
| 143 | |
| 144 | return func(newArgc, newArgv.data()); /* Launch! */ |
| 145 | } |
| 146 | |