1// Copyright (C) 2016 The Qt Company Ltd.
2// Copyright (C) 2016 Intel Corporation.
3// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
4
5#include <QtCore/qglobal.h>
6#include <QtCore/qlatin1stringview.h>
7#if QT_CONFIG(library)
8#include <QtCore/qlibrary.h>
9#include <QtCore/private/qlocking_p.h>
10#endif
11#include <QtCore/qmutex.h>
12
13#ifndef QT_NO_DBUS
14
15extern "C" void dbus_shutdown();
16
17QT_BEGIN_NAMESPACE
18
19using namespace Qt::StringLiterals;
20
21void (*qdbus_resolve_me(const char *name))();
22
23#if !defined QT_LINKED_LIBDBUS
24
25#if QT_CONFIG(library)
26Q_CONSTINIT static QLibrary *qdbus_libdbus = nullptr;
27
28void qdbus_unloadLibDBus()
29{
30 if (qdbus_libdbus) {
31 if (qEnvironmentVariableIsSet("QDBUS_FORCE_SHUTDOWN"))
32 qdbus_libdbus->resolve("dbus_shutdown")();
33 qdbus_libdbus->unload();
34 }
35 delete qdbus_libdbus;
36 qdbus_libdbus = nullptr;
37}
38#endif
39
40bool qdbus_loadLibDBus()
41{
42#if QT_CONFIG(library)
43#ifdef QT_BUILD_INTERNAL
44 // this is to simulate a library load failure for our autotest suite.
45 if (!qEnvironmentVariableIsEmpty("QT_SIMULATE_DBUS_LIBFAIL"))
46 return false;
47#endif
48
49 Q_CONSTINIT static bool triedToLoadLibrary = false;
50 Q_CONSTINIT static QBasicMutex mutex;
51 const auto locker = qt_scoped_lock(mutex);
52
53 QLibrary *&lib = qdbus_libdbus;
54 if (triedToLoadLibrary)
55 return lib && lib->isLoaded();
56
57 lib = new QLibrary;
58 lib->setLoadHints(QLibrary::ExportExternalSymbolsHint); // make libdbus symbols available for apps that need more advanced control over the dbus
59 triedToLoadLibrary = true;
60
61 static int majorversions[] = { 3, 2, -1 };
62 const QString baseNames[] = {
63#ifdef Q_OS_WIN
64 "dbus-1"_L1,
65#endif
66 "libdbus-1"_L1
67 };
68
69 lib->unload();
70 for (const int majorversion : majorversions) {
71 for (const QString &baseName : baseNames) {
72#ifdef Q_OS_WIN
73 QString suffix;
74 if (majorversion != -1)
75 suffix = QString::number(- majorversion); // negative so it prepends the dash
76 lib->setFileName(baseName + suffix);
77#else
78 lib->setFileNameAndVersion(baseName, majorversion);
79#endif
80 if (lib->load() && lib->resolve("dbus_connection_open_private"))
81 return true;
82
83 lib->unload();
84 }
85 }
86
87 delete lib;
88 lib = nullptr;
89 return false;
90#else
91 return true;
92#endif
93}
94
95void (*qdbus_resolve_conditionally(const char *name))()
96{
97#if QT_CONFIG(library)
98 if (qdbus_loadLibDBus())
99 return qdbus_libdbus->resolve(name);
100#else
101 Q_UNUSED(name);
102#endif
103 return nullptr;
104}
105
106void (*qdbus_resolve_me(const char *name))()
107{
108#if QT_CONFIG(library)
109 if (Q_UNLIKELY(!qdbus_loadLibDBus()))
110 qFatal("Cannot find libdbus-1 in your system to resolve symbol '%s'.", name);
111
112 QFunctionPointer ptr = qdbus_libdbus->resolve(name);
113 if (Q_UNLIKELY(!ptr))
114 qFatal("Cannot resolve '%s' in your libdbus-1.", name);
115
116 return ptr;
117#else
118 Q_UNUSED(name);
119 return nullptr;
120#endif
121}
122
123#else
124static void qdbus_unloadLibDBus()
125{
126 if (qEnvironmentVariableIsSet(varName: "QDBUS_FORCE_SHUTDOWN"))
127 dbus_shutdown();
128}
129
130#endif // !QT_LINKED_LIBDBUS
131
132#if defined(QT_LINKED_LIBDBUS) || QT_CONFIG(library)
133Q_DESTRUCTOR_FUNCTION(qdbus_unloadLibDBus)
134#endif
135
136QT_END_NAMESPACE
137
138#endif // QT_NO_DBUS
139

source code of qtbase/src/dbus/qdbus_symbols.cpp