]> git.ipfire.org Git - thirdparty/systemd.git/blame - src/gudev/gudevclient.c
journal: set secure deletion flags for FSS file
[thirdparty/systemd.git] / src / gudev / gudevclient.c
CommitLineData
bf05675a
DZ
1/* -*- Mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*-
2 *
cbdf255e 3 * Copyright (C) 2008-2010 David Zeuthen <davidz@redhat.com>
bf05675a
DZ
4 *
5 * This library is free software; you can redistribute it and/or
6 * modify it under the terms of the GNU Lesser General Public
7 * License as published by the Free Software Foundation; either
8 * version 2 of the License, or (at your option) any later version.
9 *
10 * This library is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 * Lesser General Public License for more details.
14 *
15 * You should have received a copy of the GNU Lesser General Public
16 * License along with this library; if not, write to the
17 * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
18 * Boston, MA 02111-1307, USA.
19 *
20 */
21
22#ifdef HAVE_CONFIG_H
23# include "config.h"
24#endif
25
26#include <stdlib.h>
27#include <string.h>
28
29#include "gudevclient.h"
30#include "gudevdevice.h"
31#include "gudevmarshal.h"
32#include "gudevprivate.h"
33
34/**
35 * SECTION:gudevclient
36 * @short_description: Query devices and listen to uevents
37 *
38 * #GUdevClient is used to query information about devices on a Linux
39 * system from the Linux kernel and the udev device
40 * manager.
41 *
42 * Device information is retrieved from the kernel (through the
43 * <literal>sysfs</literal> filesystem) and the udev daemon (through a
44 * <literal>tmpfs</literal> filesystem) and presented through
45 * #GUdevDevice objects. This means that no blocking IO ever happens
46 * (in both cases, we are essentially just reading data from kernel
47 * memory) and as such there are no asynchronous versions of the
48 * provided methods.
49 *
0976fd06 50 * To get #GUdevDevice objects, use
bf05675a
DZ
51 * g_udev_client_query_by_subsystem(),
52 * g_udev_client_query_by_device_number(),
53 * g_udev_client_query_by_device_file(),
0976fd06
DZ
54 * g_udev_client_query_by_sysfs_path(),
55 * g_udev_client_query_by_subsystem_and_name()
56 * or the #GUdevEnumerator type.
bf05675a
DZ
57 *
58 * To listen to uevents, connect to the #GUdevClient::uevent signal.
59 */
60
61struct _GUdevClientPrivate
62{
cbdf255e 63 GSource *watch_source;
bf05675a
DZ
64 struct udev *udev;
65 struct udev_monitor *monitor;
66
67 gchar **subsystems;
68};
69
70enum
71{
72 PROP_0,
73 PROP_SUBSYSTEMS,
74};
75
76enum
77{
78 UEVENT_SIGNAL,
79 LAST_SIGNAL,
80};
81
82static guint signals[LAST_SIGNAL] = { 0 };
83
84G_DEFINE_TYPE (GUdevClient, g_udev_client, G_TYPE_OBJECT)
85
86/* ---------------------------------------------------------------------------------------------------- */
87
88static gboolean
89monitor_event (GIOChannel *source,
912541b0
KS
90 GIOCondition condition,
91 gpointer data)
bf05675a
DZ
92{
93 GUdevClient *client = (GUdevClient *) data;
94 GUdevDevice *device;
95 struct udev_device *udevice;
96
e4dcdc4a
MP
97 if (client->priv->monitor == NULL)
98 goto out;
bf05675a
DZ
99 udevice = udev_monitor_receive_device (client->priv->monitor);
100 if (udevice == NULL)
101 goto out;
102
103 device = _g_udev_device_new (udevice);
104 udev_device_unref (udevice);
105 g_signal_emit (client,
106 signals[UEVENT_SIGNAL],
107 0,
108 g_udev_device_get_action (device),
109 device);
110 g_object_unref (device);
111
112 out:
113 return TRUE;
114}
115
116static void
117g_udev_client_finalize (GObject *object)
118{
119 GUdevClient *client = G_UDEV_CLIENT (object);
120
cbdf255e 121 if (client->priv->watch_source != NULL)
bf05675a 122 {
cbdf255e
DZ
123 g_source_destroy (client->priv->watch_source);
124 client->priv->watch_source = NULL;
bf05675a
DZ
125 }
126
127 if (client->priv->monitor != NULL)
128 {
129 udev_monitor_unref (client->priv->monitor);
130 client->priv->monitor = NULL;
131 }
132
133 if (client->priv->udev != NULL)
134 {
135 udev_unref (client->priv->udev);
136 client->priv->udev = NULL;
137 }
138
139 g_strfreev (client->priv->subsystems);
140
141 if (G_OBJECT_CLASS (g_udev_client_parent_class)->finalize != NULL)
142 G_OBJECT_CLASS (g_udev_client_parent_class)->finalize (object);
143}
144
145static void
146g_udev_client_set_property (GObject *object,
147 guint prop_id,
148 const GValue *value,
149 GParamSpec *pspec)
150{
151 GUdevClient *client = G_UDEV_CLIENT (object);
152
153 switch (prop_id)
154 {
155 case PROP_SUBSYSTEMS:
156 if (client->priv->subsystems != NULL)
157 g_strfreev (client->priv->subsystems);
158 client->priv->subsystems = g_strdupv (g_value_get_boxed (value));
159 break;
160
161 default:
162 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
163 break;
164 }
165}
166
167static void
168g_udev_client_get_property (GObject *object,
169 guint prop_id,
170 GValue *value,
171 GParamSpec *pspec)
172{
173 GUdevClient *client = G_UDEV_CLIENT (object);
174
175 switch (prop_id)
176 {
177 case PROP_SUBSYSTEMS:
178 g_value_set_boxed (value, client->priv->subsystems);
179 break;
180
181 default:
182 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
183 break;
184 }
185}
186
187static void
188g_udev_client_constructed (GObject *object)
189{
190 GUdevClient *client = G_UDEV_CLIENT (object);
191 GIOChannel *channel;
192 guint n;
193
194 client->priv->udev = udev_new ();
195
196 /* connect to event source */
197 client->priv->monitor = udev_monitor_new_from_netlink (client->priv->udev, "udev");
198
199 //g_debug ("ss = %p", client->priv->subsystems);
200
201 if (client->priv->subsystems != NULL)
202 {
214a6c79 203 /* install subsystem filters to only wake up for certain events */
bf05675a
DZ
204 for (n = 0; client->priv->subsystems[n] != NULL; n++)
205 {
206 gchar *subsystem;
207 gchar *devtype;
208 gchar *s;
209
210 subsystem = g_strdup (client->priv->subsystems[n]);
211 devtype = NULL;
212
213 //g_debug ("s = '%s'", subsystem);
214
215 s = strstr (subsystem, "/");
216 if (s != NULL)
217 {
218 devtype = s + 1;
219 *s = '\0';
220 }
221
e4dcdc4a
MP
222 if (client->priv->monitor != NULL)
223 udev_monitor_filter_add_match_subsystem_devtype (client->priv->monitor, subsystem, devtype);
bf05675a
DZ
224
225 g_free (subsystem);
226 }
227
228 /* listen to events, and buffer them */
e4dcdc4a
MP
229 if (client->priv->monitor != NULL)
230 {
231 udev_monitor_enable_receiving (client->priv->monitor);
232 channel = g_io_channel_unix_new (udev_monitor_get_fd (client->priv->monitor));
cbdf255e 233 client->priv->watch_source = g_io_create_watch (channel, G_IO_IN);
e4dcdc4a 234 g_io_channel_unref (channel);
cbdf255e
DZ
235 g_source_set_callback (client->priv->watch_source, (GSourceFunc) monitor_event, client, NULL);
236 g_source_attach (client->priv->watch_source, g_main_context_get_thread_default ());
237 g_source_unref (client->priv->watch_source);
238 }
239 else
240 {
241 client->priv->watch_source = NULL;
242 }
bf05675a
DZ
243 }
244
245 if (G_OBJECT_CLASS (g_udev_client_parent_class)->constructed != NULL)
246 G_OBJECT_CLASS (g_udev_client_parent_class)->constructed (object);
247}
248
249
250static void
251g_udev_client_class_init (GUdevClientClass *klass)
252{
253 GObjectClass *gobject_class = (GObjectClass *) klass;
254
255 gobject_class->constructed = g_udev_client_constructed;
256 gobject_class->set_property = g_udev_client_set_property;
257 gobject_class->get_property = g_udev_client_get_property;
258 gobject_class->finalize = g_udev_client_finalize;
259
260 /**
261 * GUdevClient:subsystems:
262 *
263 * The subsystems to listen for uevents on.
264 *
265 * To listen for only a specific DEVTYPE for a given SUBSYSTEM, use
266 * "subsystem/devtype". For example, to only listen for uevents
267 * where SUBSYSTEM is usb and DEVTYPE is usb_interface, use
268 * "usb/usb_interface".
269 *
270 * If this property is %NULL, then no events will be reported. If
271 * it's the empty array, events from all subsystems will be
272 * reported.
273 */
274 g_object_class_install_property (gobject_class,
275 PROP_SUBSYSTEMS,
276 g_param_spec_boxed ("subsystems",
277 "The subsystems to listen for changes on",
278 "The subsystems to listen for changes on",
279 G_TYPE_STRV,
280 G_PARAM_CONSTRUCT_ONLY |
281 G_PARAM_READWRITE));
282
283 /**
284 * GUdevClient::uevent:
285 * @client: The #GUdevClient receiving the event.
286 * @action: The action for the uevent e.g. "add", "remove", "change", "move", etc.
287 * @device: Details about the #GUdevDevice the event is for.
288 *
289 * Emitted when @client receives an uevent.
cbdf255e
DZ
290 *
291 * This signal is emitted in the
292 * <link linkend="g-main-context-push-thread-default">thread-default main loop</link>
293 * of the thread that @client was created in.
bf05675a
DZ
294 */
295 signals[UEVENT_SIGNAL] = g_signal_new ("uevent",
296 G_TYPE_FROM_CLASS (klass),
297 G_SIGNAL_RUN_LAST,
298 G_STRUCT_OFFSET (GUdevClientClass, uevent),
299 NULL,
300 NULL,
301 g_udev_marshal_VOID__STRING_OBJECT,
302 G_TYPE_NONE,
303 2,
304 G_TYPE_STRING,
305 G_UDEV_TYPE_DEVICE);
306
307 g_type_class_add_private (klass, sizeof (GUdevClientPrivate));
308}
309
310static void
311g_udev_client_init (GUdevClient *client)
312{
313 client->priv = G_TYPE_INSTANCE_GET_PRIVATE (client,
314 G_UDEV_TYPE_CLIENT,
315 GUdevClientPrivate);
316}
317
318/**
319 * g_udev_client_new:
daef8ae3 320 * @subsystems: (array zero-terminated=1) (element-type utf8) (transfer none) (allow-none): A %NULL terminated string array of subsystems to listen for uevents on, %NULL to not listen on uevents at all, or an empty array to listen to uevents on all subsystems. See the documentation for the #GUdevClient:subsystems property for details on this parameter.
bf05675a
DZ
321 *
322 * Constructs a #GUdevClient object that can be used to query
323 * information about devices. Connect to the #GUdevClient::uevent
cbdf255e
DZ
324 * signal to listen for uevents. Note that signals are emitted in the
325 * <link linkend="g-main-context-push-thread-default">thread-default main loop</link>
326 * of the thread that you call this constructor from.
bf05675a
DZ
327 *
328 * Returns: A new #GUdevClient object. Free with g_object_unref().
329 */
330GUdevClient *
331g_udev_client_new (const gchar * const *subsystems)
332{
333 return G_UDEV_CLIENT (g_object_new (G_UDEV_TYPE_CLIENT, "subsystems", subsystems, NULL));
334}
335
336/**
337 * g_udev_client_query_by_subsystem:
338 * @client: A #GUdevClient.
339 * @subsystem: (allow-none): The subsystem to get devices for or %NULL to get all devices.
340 *
341 * Gets all devices belonging to @subsystem.
342 *
daef8ae3 343 * Returns: (element-type GUdevDevice) (transfer full): A list of #GUdevDevice objects. The caller should free the result by using g_object_unref() on each element in the list and then g_list_free() on the list.
bf05675a
DZ
344 */
345GList *
346g_udev_client_query_by_subsystem (GUdevClient *client,
347 const gchar *subsystem)
348{
349 struct udev_enumerate *enumerate;
350 struct udev_list_entry *l, *devices;
351 GList *ret;
352
353 g_return_val_if_fail (G_UDEV_IS_CLIENT (client), NULL);
354
355 ret = NULL;
356
357 /* prepare a device scan */
358 enumerate = udev_enumerate_new (client->priv->udev);
359
360 /* filter for subsystem */
361 if (subsystem != NULL)
362 udev_enumerate_add_match_subsystem (enumerate, subsystem);
363 /* retrieve the list */
364 udev_enumerate_scan_devices (enumerate);
365
366 /* add devices to the list */
367 devices = udev_enumerate_get_list_entry (enumerate);
368 for (l = devices; l != NULL; l = udev_list_entry_get_next (l))
369 {
370 struct udev_device *udevice;
371 GUdevDevice *device;
372
373 udevice = udev_device_new_from_syspath (udev_enumerate_get_udev (enumerate),
374 udev_list_entry_get_name (l));
375 if (udevice == NULL)
376 continue;
377 device = _g_udev_device_new (udevice);
378 udev_device_unref (udevice);
379 ret = g_list_prepend (ret, device);
380 }
381 udev_enumerate_unref (enumerate);
382
383 ret = g_list_reverse (ret);
384
385 return ret;
386}
387
388/**
389 * g_udev_client_query_by_device_number:
390 * @client: A #GUdevClient.
391 * @type: A value from the #GUdevDeviceType enumeration.
392 * @number: A device number.
393 *
394 * Looks up a device for a type and device number.
395 *
daef8ae3 396 * Returns: (transfer full): A #GUdevDevice object or %NULL if the device was not found. Free with g_object_unref().
bf05675a
DZ
397 */
398GUdevDevice *
399g_udev_client_query_by_device_number (GUdevClient *client,
400 GUdevDeviceType type,
401 GUdevDeviceNumber number)
402{
403 struct udev_device *udevice;
404 GUdevDevice *device;
405
406 g_return_val_if_fail (G_UDEV_IS_CLIENT (client), NULL);
407
408 device = NULL;
409 udevice = udev_device_new_from_devnum (client->priv->udev, type, number);
410
411 if (udevice == NULL)
412 goto out;
413
414 device = _g_udev_device_new (udevice);
415 udev_device_unref (udevice);
416
417 out:
418 return device;
419}
420
421/**
422 * g_udev_client_query_by_device_file:
423 * @client: A #GUdevClient.
424 * @device_file: A device file.
425 *
426 * Looks up a device for a device file.
427 *
daef8ae3 428 * Returns: (transfer full): A #GUdevDevice object or %NULL if the device was not found. Free with g_object_unref().
bf05675a
DZ
429 */
430GUdevDevice *
431g_udev_client_query_by_device_file (GUdevClient *client,
432 const gchar *device_file)
433{
434 struct stat stat_buf;
435 GUdevDevice *device;
436
437 g_return_val_if_fail (G_UDEV_IS_CLIENT (client), NULL);
438 g_return_val_if_fail (device_file != NULL, NULL);
439
440 device = NULL;
441
442 if (stat (device_file, &stat_buf) != 0)
443 goto out;
444
445 if (stat_buf.st_rdev == 0)
446 goto out;
447
448 if (S_ISBLK (stat_buf.st_mode))
449 device = g_udev_client_query_by_device_number (client, G_UDEV_DEVICE_TYPE_BLOCK, stat_buf.st_rdev);
450 else if (S_ISCHR (stat_buf.st_mode))
451 device = g_udev_client_query_by_device_number (client, G_UDEV_DEVICE_TYPE_CHAR, stat_buf.st_rdev);
452
453 out:
454 return device;
455}
456
457/**
458 * g_udev_client_query_by_sysfs_path:
459 * @client: A #GUdevClient.
460 * @sysfs_path: A sysfs path.
461 *
462 * Looks up a device for a sysfs path.
079de714
KS
463 *
464 * Returns: (transfer full): A #GUdevDevice object or %NULL if the device was not found. Free with g_object_unref().
bf05675a
DZ
465 */
466GUdevDevice *
467g_udev_client_query_by_sysfs_path (GUdevClient *client,
468 const gchar *sysfs_path)
469{
470 struct udev_device *udevice;
471 GUdevDevice *device;
472
473 g_return_val_if_fail (G_UDEV_IS_CLIENT (client), NULL);
474 g_return_val_if_fail (sysfs_path != NULL, NULL);
475
476 device = NULL;
477 udevice = udev_device_new_from_syspath (client->priv->udev, sysfs_path);
478 if (udevice == NULL)
479 goto out;
480
481 device = _g_udev_device_new (udevice);
482 udev_device_unref (udevice);
483
484 out:
485 return device;
486}
487
488/**
489 * g_udev_client_query_by_subsystem_and_name:
490 * @client: A #GUdevClient.
491 * @subsystem: A subsystem name.
492 * @name: The name of the device.
493 *
494 * Looks up a device for a subsystem and name.
495 *
daef8ae3 496 * Returns: (transfer full): A #GUdevDevice object or %NULL if the device was not found. Free with g_object_unref().
bf05675a
DZ
497 */
498GUdevDevice *
499g_udev_client_query_by_subsystem_and_name (GUdevClient *client,
500 const gchar *subsystem,
501 const gchar *name)
502{
503 struct udev_device *udevice;
504 GUdevDevice *device;
505
506 g_return_val_if_fail (G_UDEV_IS_CLIENT (client), NULL);
507 g_return_val_if_fail (subsystem != NULL, NULL);
508 g_return_val_if_fail (name != NULL, NULL);
509
510 device = NULL;
511 udevice = udev_device_new_from_subsystem_sysname (client->priv->udev, subsystem, name);
512 if (udevice == NULL)
513 goto out;
514
515 device = _g_udev_device_new (udevice);
516 udev_device_unref (udevice);
517
518 out:
519 return device;
520}
521
0976fd06
DZ
522struct udev *
523_g_udev_client_get_udev (GUdevClient *client)
524{
525 g_return_val_if_fail (G_UDEV_IS_CLIENT (client), NULL);
526 return client->priv->udev;
527}