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 | |