chiark / gitweb /
driverd: implement AddMatch/RemoveMatch logic
[elogind.git] / src / gudev / gudevenumerator.c
1 /* -*- Mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*-
2  *
3  * Copyright (C) 2008-2010 David Zeuthen <davidz@redhat.com>
4  *
5  * This library is free software; you can redistribute it and/or
6  * modify it under the terms of the GNU Library 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  * Library General Public License for more details.
14  *
15  * You should have received a copy of the GNU Library General Public
16  * License along with this library; if not, write to the Free Software
17  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
18  */
19
20 #ifdef HAVE_CONFIG_H
21 #  include "config.h"
22 #endif
23
24 #include <stdlib.h>
25 #include <string.h>
26
27 #include "gudevclient.h"
28 #include "gudevenumerator.h"
29 #include "gudevdevice.h"
30 #include "gudevmarshal.h"
31 #include "gudevprivate.h"
32
33 /**
34  * SECTION:gudevenumerator
35  * @short_description: Lookup and sort devices
36  *
37  * #GUdevEnumerator is used to lookup and sort devices.
38  *
39  * Since: 165
40  */
41
42 struct _GUdevEnumeratorPrivate
43 {
44   GUdevClient *client;
45   struct udev_enumerate *e;
46 };
47
48 enum
49 {
50   PROP_0,
51   PROP_CLIENT,
52 };
53
54 G_DEFINE_TYPE (GUdevEnumerator, g_udev_enumerator, G_TYPE_OBJECT)
55
56 /* ---------------------------------------------------------------------------------------------------- */
57
58 static void
59 g_udev_enumerator_finalize (GObject *object)
60 {
61   GUdevEnumerator *enumerator = G_UDEV_ENUMERATOR (object);
62
63   if (enumerator->priv->client != NULL)
64     {
65       g_object_unref (enumerator->priv->client);
66       enumerator->priv->client = NULL;
67     }
68
69   if (enumerator->priv->e != NULL)
70     {
71       udev_enumerate_unref (enumerator->priv->e);
72       enumerator->priv->e = NULL;
73     }
74
75   if (G_OBJECT_CLASS (g_udev_enumerator_parent_class)->finalize != NULL)
76     G_OBJECT_CLASS (g_udev_enumerator_parent_class)->finalize (object);
77 }
78
79 static void
80 g_udev_enumerator_set_property (GObject      *object,
81                                 guint         prop_id,
82                                 const GValue *value,
83                                 GParamSpec   *pspec)
84 {
85   GUdevEnumerator *enumerator = G_UDEV_ENUMERATOR (object);
86
87   switch (prop_id)
88     {
89     case PROP_CLIENT:
90       if (enumerator->priv->client != NULL)
91         g_object_unref (enumerator->priv->client);
92       enumerator->priv->client = g_value_dup_object (value);
93       break;
94
95     default:
96       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
97       break;
98     }
99 }
100
101 static void
102 g_udev_enumerator_get_property (GObject     *object,
103                                 guint        prop_id,
104                                 GValue      *value,
105                                 GParamSpec  *pspec)
106 {
107   GUdevEnumerator *enumerator = G_UDEV_ENUMERATOR (object);
108
109   switch (prop_id)
110     {
111     case PROP_CLIENT:
112       g_value_set_object (value, enumerator->priv->client);
113       break;
114
115     default:
116       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
117       break;
118     }
119 }
120
121 static void
122 g_udev_enumerator_constructed (GObject *object)
123 {
124   GUdevEnumerator *enumerator = G_UDEV_ENUMERATOR (object);
125
126   g_assert (G_UDEV_IS_CLIENT (enumerator->priv->client));
127
128   enumerator->priv->e = udev_enumerate_new (_g_udev_client_get_udev (enumerator->priv->client));
129
130   if (G_OBJECT_CLASS (g_udev_enumerator_parent_class)->constructed != NULL)
131     G_OBJECT_CLASS (g_udev_enumerator_parent_class)->constructed (object);
132 }
133
134 static void
135 g_udev_enumerator_class_init (GUdevEnumeratorClass *klass)
136 {
137   GObjectClass *gobject_class = (GObjectClass *) klass;
138
139   gobject_class->finalize     = g_udev_enumerator_finalize;
140   gobject_class->set_property = g_udev_enumerator_set_property;
141   gobject_class->get_property = g_udev_enumerator_get_property;
142   gobject_class->constructed  = g_udev_enumerator_constructed;
143
144   /**
145    * GUdevEnumerator:client:
146    *
147    * The #GUdevClient to enumerate devices from.
148    *
149    * Since: 165
150    */
151   g_object_class_install_property (gobject_class,
152                                    PROP_CLIENT,
153                                    g_param_spec_object ("client",
154                                                         "The client to enumerate devices from",
155                                                         "The client to enumerate devices from",
156                                                         G_UDEV_TYPE_CLIENT,
157                                                         G_PARAM_CONSTRUCT_ONLY |
158                                                         G_PARAM_READWRITE));
159
160   g_type_class_add_private (klass, sizeof (GUdevEnumeratorPrivate));
161 }
162
163 static void
164 g_udev_enumerator_init (GUdevEnumerator *enumerator)
165 {
166   enumerator->priv = G_TYPE_INSTANCE_GET_PRIVATE (enumerator,
167                                                   G_UDEV_TYPE_ENUMERATOR,
168                                                   GUdevEnumeratorPrivate);
169 }
170
171 /**
172  * g_udev_enumerator_new:
173  * @client: A #GUdevClient to enumerate devices from.
174  *
175  * Constructs a #GUdevEnumerator object that can be used to enumerate
176  * and sort devices. Use the add_match_*() and add_nomatch_*() methods
177  * and execute the query to get a list of devices with
178  * g_udev_enumerator_execute().
179  *
180  * Returns: A new #GUdevEnumerator object. Free with g_object_unref().
181  *
182  * Since: 165
183  */
184 GUdevEnumerator *
185 g_udev_enumerator_new (GUdevClient *client)
186 {
187   g_return_val_if_fail (G_UDEV_IS_CLIENT (client), NULL);
188   return G_UDEV_ENUMERATOR (g_object_new (G_UDEV_TYPE_ENUMERATOR, "client", client, NULL));
189 }
190
191
192 /**
193  * g_udev_enumerator_add_match_subsystem:
194  * @enumerator: A #GUdevEnumerator.
195  * @subsystem: Wildcard for subsystem name e.g. 'scsi' or 'a*'.
196  *
197  * All returned devices will match the given @subsystem.
198  *
199  * Returns: (transfer none): The passed in @enumerator.
200  *
201  * Since: 165
202  */
203 GUdevEnumerator *
204 g_udev_enumerator_add_match_subsystem (GUdevEnumerator  *enumerator,
205                                        const gchar      *subsystem)
206 {
207   g_return_val_if_fail (G_UDEV_IS_ENUMERATOR (enumerator), NULL);
208   g_return_val_if_fail (subsystem != NULL, NULL);
209   udev_enumerate_add_match_subsystem (enumerator->priv->e, subsystem);
210   return enumerator;
211 }
212
213 /**
214  * g_udev_enumerator_add_nomatch_subsystem:
215  * @enumerator: A #GUdevEnumerator.
216  * @subsystem: Wildcard for subsystem name e.g. 'scsi' or 'a*'.
217  *
218  * All returned devices will not match the given @subsystem.
219  *
220  * Returns: (transfer none): The passed in @enumerator.
221  *
222  * Since: 165
223  */
224 GUdevEnumerator *
225 g_udev_enumerator_add_nomatch_subsystem (GUdevEnumerator  *enumerator,
226                                          const gchar      *subsystem)
227 {
228   g_return_val_if_fail (G_UDEV_IS_ENUMERATOR (enumerator), NULL);
229   g_return_val_if_fail (subsystem != NULL, NULL);
230   udev_enumerate_add_nomatch_subsystem (enumerator->priv->e, subsystem);
231   return enumerator;
232 }
233
234 /**
235  * g_udev_enumerator_add_match_sysfs_attr:
236  * @enumerator: A #GUdevEnumerator.
237  * @name: Wildcard filter for sysfs attribute key.
238  * @value: Wildcard filter for sysfs attribute value.
239  *
240  * All returned devices will have a sysfs attribute matching the given @name and @value.
241  *
242  * Returns: (transfer none): The passed in @enumerator.
243  *
244  * Since: 165
245  */
246 GUdevEnumerator *
247 g_udev_enumerator_add_match_sysfs_attr (GUdevEnumerator  *enumerator,
248                                         const gchar      *name,
249                                         const gchar      *value)
250 {
251   g_return_val_if_fail (G_UDEV_IS_ENUMERATOR (enumerator), NULL);
252   g_return_val_if_fail (name != NULL, NULL);
253   g_return_val_if_fail (value != NULL, NULL);
254   udev_enumerate_add_match_sysattr (enumerator->priv->e, name, value);
255   return enumerator;
256 }
257
258 /**
259  * g_udev_enumerator_add_nomatch_sysfs_attr:
260  * @enumerator: A #GUdevEnumerator.
261  * @name: Wildcard filter for sysfs attribute key.
262  * @value: Wildcard filter for sysfs attribute value.
263  *
264  * All returned devices will not have a sysfs attribute matching the given @name and @value.
265  *
266  * Returns: (transfer none): The passed in @enumerator.
267  *
268  * Since: 165
269  */
270 GUdevEnumerator *
271 g_udev_enumerator_add_nomatch_sysfs_attr (GUdevEnumerator  *enumerator,
272                                           const gchar      *name,
273                                           const gchar      *value)
274 {
275   g_return_val_if_fail (G_UDEV_IS_ENUMERATOR (enumerator), NULL);
276   g_return_val_if_fail (name != NULL, NULL);
277   g_return_val_if_fail (value != NULL, NULL);
278   udev_enumerate_add_nomatch_sysattr (enumerator->priv->e, name, value);
279   return enumerator;
280 }
281
282 /**
283  * g_udev_enumerator_add_match_property:
284  * @enumerator: A #GUdevEnumerator.
285  * @name: Wildcard filter for property name.
286  * @value: Wildcard filter for property value.
287  *
288  * All returned devices will have a property matching the given @name and @value.
289  *
290  * Returns: (transfer none): The passed in @enumerator.
291  *
292  * Since: 165
293  */
294 GUdevEnumerator *
295 g_udev_enumerator_add_match_property (GUdevEnumerator  *enumerator,
296                                       const gchar      *name,
297                                       const gchar      *value)
298 {
299   g_return_val_if_fail (G_UDEV_IS_ENUMERATOR (enumerator), NULL);
300   g_return_val_if_fail (name != NULL, NULL);
301   g_return_val_if_fail (value != NULL, NULL);
302   udev_enumerate_add_match_property (enumerator->priv->e, name, value);
303   return enumerator;
304 }
305
306 /**
307  * g_udev_enumerator_add_match_name:
308  * @enumerator: A #GUdevEnumerator.
309  * @name: Wildcard filter for kernel name e.g. "sda*".
310  *
311  * All returned devices will match the given @name.
312  *
313  * Returns: (transfer none): The passed in @enumerator.
314  *
315  * Since: 165
316  */
317 GUdevEnumerator *
318 g_udev_enumerator_add_match_name (GUdevEnumerator  *enumerator,
319                                   const gchar      *name)
320 {
321   g_return_val_if_fail (G_UDEV_IS_ENUMERATOR (enumerator), NULL);
322   g_return_val_if_fail (name != NULL, NULL);
323   udev_enumerate_add_match_sysname (enumerator->priv->e, name);
324   return enumerator;
325 }
326
327 /**
328  * g_udev_enumerator_add_sysfs_path:
329  * @enumerator: A #GUdevEnumerator.
330  * @sysfs_path: A sysfs path, e.g. "/sys/devices/pci0000:00/0000:00:1f.2/host0/target0:0:0/0:0:0:0/block/sda"
331  *
332  * Add a device to the list of devices, to retrieve it back sorted in dependency order.
333  *
334  * Returns: (transfer none): The passed in @enumerator.
335  *
336  * Since: 165
337  */
338 GUdevEnumerator *
339 g_udev_enumerator_add_sysfs_path (GUdevEnumerator  *enumerator,
340                                   const gchar      *sysfs_path)
341 {
342   g_return_val_if_fail (G_UDEV_IS_ENUMERATOR (enumerator), NULL);
343   g_return_val_if_fail (sysfs_path != NULL, NULL);
344   udev_enumerate_add_syspath (enumerator->priv->e, sysfs_path);
345   return enumerator;
346 }
347
348 /**
349  * g_udev_enumerator_add_match_tag:
350  * @enumerator: A #GUdevEnumerator.
351  * @tag: A udev tag e.g. "udev-acl".
352  *
353  * All returned devices will match the given @tag.
354  *
355  * Returns: (transfer none): The passed in @enumerator.
356  *
357  * Since: 165
358  */
359 GUdevEnumerator *
360 g_udev_enumerator_add_match_tag (GUdevEnumerator  *enumerator,
361                                  const gchar      *tag)
362 {
363   g_return_val_if_fail (G_UDEV_IS_ENUMERATOR (enumerator), NULL);
364   g_return_val_if_fail (tag != NULL, NULL);
365   udev_enumerate_add_match_tag (enumerator->priv->e, tag);
366   return enumerator;
367 }
368
369 /**
370  * g_udev_enumerator_add_match_is_initialized:
371  * @enumerator: A #GUdevEnumerator.
372  *
373  * All returned devices will be initialized.
374  *
375  * Returns: (transfer none): The passed in @enumerator.
376  *
377  * Since: 165
378  */
379 GUdevEnumerator *
380 g_udev_enumerator_add_match_is_initialized (GUdevEnumerator  *enumerator)
381 {
382   g_return_val_if_fail (G_UDEV_IS_ENUMERATOR (enumerator), NULL);
383   udev_enumerate_add_match_is_initialized (enumerator->priv->e);
384   return enumerator;
385 }
386
387 /**
388  * g_udev_enumerator_execute:
389  * @enumerator: A #GUdevEnumerator.
390  *
391  * Executes the query in @enumerator.
392  *
393  * 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.
394  *
395  * Since: 165
396  */
397 GList *
398 g_udev_enumerator_execute (GUdevEnumerator  *enumerator)
399 {
400   GList *ret;
401   struct udev_list_entry *l, *devices;
402
403   g_return_val_if_fail (G_UDEV_IS_ENUMERATOR (enumerator), NULL);
404
405   ret = NULL;
406
407   /* retrieve the list */
408   udev_enumerate_scan_devices (enumerator->priv->e);
409
410   devices = udev_enumerate_get_list_entry (enumerator->priv->e);
411   for (l = devices; l != NULL; l = udev_list_entry_get_next (l))
412     {
413       struct udev_device *udevice;
414       GUdevDevice *device;
415
416       udevice = udev_device_new_from_syspath (udev_enumerate_get_udev (enumerator->priv->e),
417                                               udev_list_entry_get_name (l));
418       if (udevice == NULL)
419         continue;
420
421       device = _g_udev_device_new (udevice);
422       udev_device_unref (udevice);
423       ret = g_list_prepend (ret, device);
424     }
425
426   ret = g_list_reverse (ret);
427
428   return ret;
429 }