1/****************************************************************************
2**
3** Copyright (C) 2016 The Qt Company Ltd.
4** Copyright (C) 2016 Intel Corporation.
5** Contact: https://www.qt.io/licensing/
6**
7** This file is part of the QtDBus module of the Qt Toolkit.
8**
9** $QT_BEGIN_LICENSE:LGPL$
10** Commercial License Usage
11** Licensees holding valid commercial Qt licenses may use this file in
12** accordance with the commercial license agreement provided with the
13** Software or, alternatively, in accordance with the terms contained in
14** a written agreement between you and The Qt Company. For licensing terms
15** and conditions see https://www.qt.io/terms-conditions. For further
16** information use the contact form at https://www.qt.io/contact-us.
17**
18** GNU Lesser General Public License Usage
19** Alternatively, this file may be used under the terms of the GNU Lesser
20** General Public License version 3 as published by the Free Software
21** Foundation and appearing in the file LICENSE.LGPL3 included in the
22** packaging of this file. Please review the following information to
23** ensure the GNU Lesser General Public License version 3 requirements
24** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
25**
26** GNU General Public License Usage
27** Alternatively, this file may be used under the terms of the GNU
28** General Public License version 2.0 or (at your option) the GNU General
29** Public license version 3 or any later version approved by the KDE Free
30** Qt Foundation. The licenses are as published by the Free Software
31** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
32** included in the packaging of this file. Please review the following
33** information to ensure the GNU General Public License requirements will
34** be met: https://www.gnu.org/licenses/gpl-2.0.html and
35** https://www.gnu.org/licenses/gpl-3.0.html.
36**
37** $QT_END_LICENSE$
38**
39****************************************************************************/
40
41#include <QtCore/qglobal.h>
42#if QT_CONFIG(library)
43#include <QtCore/qlibrary.h>
44#include <QtCore/private/qlocking_p.h>
45#endif
46#include <QtCore/qmutex.h>
47
48#ifndef QT_NO_DBUS
49
50extern "C" void dbus_shutdown();
51
52QT_BEGIN_NAMESPACE
53
54void (*qdbus_resolve_me(const char *name))();
55
56#if !defined QT_LINKED_LIBDBUS
57
58#if QT_CONFIG(library)
59static QLibrary *qdbus_libdbus = nullptr;
60
61void qdbus_unloadLibDBus()
62{
63 if (qdbus_libdbus) {
64 if (qEnvironmentVariableIsSet("QDBUS_FORCE_SHUTDOWN"))
65 qdbus_libdbus->resolve("dbus_shutdown")();
66 qdbus_libdbus->unload();
67 }
68 delete qdbus_libdbus;
69 qdbus_libdbus = nullptr;
70}
71#endif
72
73bool qdbus_loadLibDBus()
74{
75#if QT_CONFIG(library)
76#ifdef QT_BUILD_INTERNAL
77 // this is to simulate a library load failure for our autotest suite.
78 if (!qEnvironmentVariableIsEmpty("QT_SIMULATE_DBUS_LIBFAIL"))
79 return false;
80#endif
81
82 static bool triedToLoadLibrary = false;
83 static QBasicMutex mutex;
84 const auto locker = qt_scoped_lock(mutex);
85
86 QLibrary *&lib = qdbus_libdbus;
87 if (triedToLoadLibrary)
88 return lib && lib->isLoaded();
89
90 lib = new QLibrary;
91 lib->setLoadHints(QLibrary::ExportExternalSymbolsHint); // make libdbus symbols available for apps that need more advanced control over the dbus
92 triedToLoadLibrary = true;
93
94 static int majorversions[] = { 3, 2, -1 };
95 const QString baseNames[] = {
96#ifdef Q_OS_WIN
97 QLatin1String("dbus-1"),
98#endif
99 QLatin1String("libdbus-1")
100 };
101
102 lib->unload();
103 for (const int majorversion : majorversions) {
104 for (const QString &baseName : baseNames) {
105#ifdef Q_OS_WIN
106 QString suffix;
107 if (majorversion != -1)
108 suffix = QString::number(- majorversion); // negative so it prepends the dash
109 lib->setFileName(baseName + suffix);
110#else
111 lib->setFileNameAndVersion(baseName, majorversion);
112#endif
113 if (lib->load() && lib->resolve("dbus_connection_open_private"))
114 return true;
115
116 lib->unload();
117 }
118 }
119
120 delete lib;
121 lib = nullptr;
122 return false;
123#else
124 return true;
125#endif
126}
127
128void (*qdbus_resolve_conditionally(const char *name))()
129{
130#if QT_CONFIG(library)
131 if (qdbus_loadLibDBus())
132 return qdbus_libdbus->resolve(name);
133#else
134 Q_UNUSED(name);
135#endif
136 return nullptr;
137}
138
139void (*qdbus_resolve_me(const char *name))()
140{
141#if QT_CONFIG(library)
142 if (Q_UNLIKELY(!qdbus_loadLibDBus()))
143 qFatal("Cannot find libdbus-1 in your system to resolve symbol '%s'.", name);
144
145 QFunctionPointer ptr = qdbus_libdbus->resolve(name);
146 if (Q_UNLIKELY(!ptr))
147 qFatal("Cannot resolve '%s' in your libdbus-1.", name);
148
149 return ptr;
150#else
151 Q_UNUSED(name);
152 return nullptr;
153#endif
154}
155
156#else
157static void qdbus_unloadLibDBus()
158{
159 if (qEnvironmentVariableIsSet("QDBUS_FORCE_SHUTDOWN"))
160 dbus_shutdown();
161}
162
163#endif // !QT_LINKED_LIBDBUS
164
165#if defined(QT_LINKED_LIBDBUS) || QT_CONFIG(library)
166Q_DESTRUCTOR_FUNCTION(qdbus_unloadLibDBus)
167#endif
168
169QT_END_NAMESPACE
170
171#endif // QT_NO_DBUS
172