Solid

udevqtclient.cpp
1/*
2 SPDX-FileCopyrightText: 2009 Benjamin K. Stuhl <bks24@cornell.edu>
3
4 SPDX-License-Identifier: LGPL-2.1-only OR LGPL-3.0-only OR LicenseRef-KDE-Accepted-LGPL
5*/
6
7#include "udevqtclient.h"
8#include "udevqt_p.h"
9
10#include "devices_debug.h"
11
12#include <QSocketNotifier>
13#include <qplatformdefs.h>
14
15namespace UdevQt
16{
17ClientPrivate::ClientPrivate(Client *q_)
18 : udev(nullptr)
19 , monitor(nullptr)
20 , q(q_)
21 , monitorNotifier(nullptr)
22{
23}
24
25ClientPrivate::~ClientPrivate()
26{
27 udev_unref(udev);
28 delete monitorNotifier;
29
30 if (monitor) {
31 udev_monitor_unref(monitor);
32 }
33}
34
35void ClientPrivate::init(const QStringList &subsystemList, ListenToWhat what)
36{
37 udev = udev_new();
38
39 if (what != ListenToNone) {
40 setWatchedSubsystems(subsystemList);
41 }
42}
43
44void ClientPrivate::setWatchedSubsystems(const QStringList &subsystemList)
45{
46 // create a listener
47 struct udev_monitor *newM = udev_monitor_new_from_netlink(udev, "udev");
48
49 if (!newM) {
50 qWarning("UdevQt: unable to create udev monitor connection");
51 return;
52 }
53
54 // apply our filters; an empty list means listen to everything
55 for (const QString &subsysDevtype : subsystemList) {
56 int ix = subsysDevtype.indexOf("/");
57
58 if (ix > 0) {
59 QByteArray subsystem = subsysDevtype.left(ix).toLatin1();
60 QByteArray devType = subsysDevtype.mid(ix + 1).toLatin1();
61 udev_monitor_filter_add_match_subsystem_devtype(newM, subsystem.constData(), devType.constData());
62 } else {
63 udev_monitor_filter_add_match_subsystem_devtype(newM, subsysDevtype.toLatin1().constData(), nullptr);
64 }
65 }
66
67 // start the new monitor receiving
68 udev_monitor_enable_receiving(newM);
69 QSocketNotifier *sn = new QSocketNotifier(udev_monitor_get_fd(newM), QSocketNotifier::Read);
71 dispatchEvent();
72 });
73
74 // kill any previous monitor
75 delete monitorNotifier;
76 if (monitor) {
77 udev_monitor_unref(monitor);
78 }
79
80 // and save our new one
81 monitor = newM;
82 monitorNotifier = sn;
83 watchedSubsystems = subsystemList;
84}
85
86void ClientPrivate::dispatchEvent()
87{
88 monitorNotifier->setEnabled(false);
89 struct udev_device *dev = udev_monitor_receive_device(monitor);
90 monitorNotifier->setEnabled(true);
91
92 if (!dev) {
93 return;
94 }
95
96 Device device(new DevicePrivate(dev, false));
97
98 QByteArray action(udev_device_get_action(dev));
99 if (action == "add") {
100 Q_EMIT q->deviceAdded(device);
101 } else if (action == "remove") {
102 Q_EMIT q->deviceRemoved(device);
103 } else if (action == "change") {
104 Q_EMIT q->deviceChanged(device);
105 } else if (action == "online") {
106 Q_EMIT q->deviceOnlined(device);
107 } else if (action == "offline") {
108 Q_EMIT q->deviceOfflined(device);
109 } else if (action == "bind") {
110 Q_EMIT q->deviceBound(device);
111 } else if (action == "unbind") {
112 Q_EMIT q->deviceUnbound(device);
113 } else {
114 qCDebug(Solid::Frontend::DeviceManager::DEVICEMANAGER) << "UdevQt: unhandled action:" << action.constData() << "for device:" << device.sysfsPath();
115 }
116}
117
118DeviceList ClientPrivate::deviceListFromEnumerate(struct udev_enumerate *en)
119{
120 DeviceList ret;
121 struct udev_list_entry *list;
122 struct udev_list_entry *entry;
123
124 udev_enumerate_scan_devices(en);
125 list = udev_enumerate_get_list_entry(en);
126 udev_list_entry_foreach(entry, list)
127 {
128 struct udev_device *ud = udev_device_new_from_syspath(udev_enumerate_get_udev(en), udev_list_entry_get_name(entry));
129
130 if (!ud) {
131 continue;
132 }
133
134 ret << Device(new DevicePrivate(ud, false));
135 }
136
137 udev_enumerate_unref(en);
138
139 return ret;
140}
141
142Client::Client(QObject *parent)
143 : QObject(parent)
144 , d(new ClientPrivate(this))
145{
146 d->init(QStringList(), ClientPrivate::ListenToNone);
147}
148
149Client::Client(const QStringList &subsystemList, QObject *parent)
150 : QObject(parent)
151 , d(new ClientPrivate(this))
152{
153 d->init(subsystemList, ClientPrivate::ListenToList);
154}
155
156Client::~Client()
157{
158 delete d;
159}
160
161QStringList Client::watchedSubsystems() const
162{
163 // we're watching a specific list
164 if (!d->watchedSubsystems.isEmpty()) {
165 return d->watchedSubsystems;
166 }
167
168 // we're not watching anything
169 if (!d->monitor) {
170 return QStringList();
171 }
172
173 // we're watching everything: figure out what "everything" currently is
174 // we don't cache it, since it may be subject to change, depending on hotplug
175 struct udev_enumerate *en = udev_enumerate_new(d->udev);
176 udev_enumerate_scan_subsystems(en);
177 QStringList s = listFromListEntry(udev_enumerate_get_list_entry(en));
178 udev_enumerate_unref(en);
179 return s;
180}
181
182void Client::setWatchedSubsystems(const QStringList &subsystemList)
183{
184 d->setWatchedSubsystems(subsystemList);
185}
186
187DeviceList Client::devicesByProperty(const QString &property, const QVariant &value)
188{
189 struct udev_enumerate *en = udev_enumerate_new(d->udev);
190
191 if (value.isValid()) {
192 udev_enumerate_add_match_property(en, property.toLatin1().constData(), value.toString().toLatin1().constData());
193 } else {
194 udev_enumerate_add_match_property(en, property.toLatin1().constData(), nullptr);
195 }
196
197 return d->deviceListFromEnumerate(en);
198}
199
200DeviceList Client::allDevices()
201{
202 struct udev_enumerate *en = udev_enumerate_new(d->udev);
203 return d->deviceListFromEnumerate(en);
204}
205
206DeviceList Client::devicesBySubsystem(const QString &subsystem)
207{
208 struct udev_enumerate *en = udev_enumerate_new(d->udev);
209
210 udev_enumerate_add_match_subsystem(en, subsystem.toLatin1().constData());
211 return d->deviceListFromEnumerate(en);
212}
213
214DeviceList Client::devicesBySubsystemsAndProperties(const QStringList &subsystems, const QVariantMap &properties)
215{
216 struct udev_enumerate *en = udev_enumerate_new(d->udev);
217
218 for (const QString &subsystem : subsystems) {
219 udev_enumerate_add_match_subsystem(en, subsystem.toLatin1().constData());
220 }
221
222 for (auto it = properties.begin(), end = properties.end(); it != end; ++it) {
223 if (it.value().isValid()) {
224 udev_enumerate_add_match_property(en, it.key().toLatin1().constData(), it.value().toString().toLatin1().constData());
225 } else {
226 udev_enumerate_add_match_property(en, it.key().toLatin1().constData(), nullptr);
227 }
228 }
229
230 return d->deviceListFromEnumerate(en);
231}
232
233Device Client::deviceByDeviceFile(const QString &deviceFile)
234{
235 QT_STATBUF sb;
236
237 if (QT_STAT(deviceFile.toLatin1().constData(), &sb) != 0) {
238 return Device();
239 }
240
241 struct udev_device *ud = nullptr;
242
243 if (S_ISBLK(sb.st_mode)) {
244 ud = udev_device_new_from_devnum(d->udev, 'b', sb.st_rdev);
245 } else if (S_ISCHR(sb.st_mode)) {
246 ud = udev_device_new_from_devnum(d->udev, 'c', sb.st_rdev);
247 }
248
249 if (!ud) {
250 return Device();
251 }
252
253 return Device(new DevicePrivate(ud, false));
254}
255
256Device Client::deviceBySysfsPath(const QString &sysfsPath)
257{
258 struct udev_device *ud = udev_device_new_from_syspath(d->udev, sysfsPath.toLatin1().constData());
259
260 if (!ud) {
261 return Device();
262 }
263
264 return Device(new DevicePrivate(ud, false));
265}
266
267Device Client::deviceBySubsystemAndName(const QString &subsystem, const QString &name)
268{
269 struct udev_device *ud = udev_device_new_from_subsystem_sysname(d->udev, //
270 subsystem.toLatin1().constData(),
272
273 if (!ud) {
274 return Device();
275 }
276
277 return Device(new DevicePrivate(ud, false));
278}
279
280}
281
282#include "moc_udevqtclient.cpp"
QString name(GameStandardAction id)
QAction * end(const QObject *recvr, const char *slot, QObject *parent)
KIOCORE_EXPORT QStringList list(const QString &fileClass)
KGuiItem properties()
const char * constData() const const
QByteArray left(qsizetype len) const const
QByteArray mid(qsizetype pos, qsizetype len) const const
QMetaObject::Connection connect(const QObject *sender, PointerToMemberFunction signal, Functor functor)
void activated(QSocketDescriptor socket, QSocketNotifier::Type type)
QByteArray toLatin1() const const
bool isValid() const const
QString toString() const const
This file is part of the KDE documentation.
Documentation copyright © 1996-2024 The KDE developers.
Generated on Fri Jul 26 2024 11:51:14 by doxygen 1.11.0 written by Dimitri van Heesch, © 1997-2006

KDE's Doxygen guidelines are available online.