]>
Commit | Line | Data |
---|---|---|
88a6477e KS |
1 | /*** |
2 | This file is part of systemd. | |
3 | ||
4 | Copyright 2008-2012 Kay Sievers <kay@vrfy.org> | |
f4ac4d1a | 5 | Copyright 2015 Tom Gundersen <teg@jklm.no> |
88a6477e KS |
6 | |
7 | systemd is free software; you can redistribute it and/or modify it | |
8 | under the terms of the GNU Lesser General Public License as published by | |
9 | the Free Software Foundation; either version 2.1 of the License, or | |
10 | (at your option) any later version. | |
11 | ||
12 | systemd is distributed in the hope that it will be useful, but | |
13 | WITHOUT ANY WARRANTY; without even the implied warranty of | |
14 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | |
15 | Lesser General Public License for more details. | |
16 | ||
17 | You should have received a copy of the GNU Lesser General Public License | |
18 | along with systemd; If not, see <http://www.gnu.org/licenses/>. | |
19 | ***/ | |
eb1f0e66 | 20 | |
07630cea | 21 | #include <ctype.h> |
eb1f0e66 | 22 | #include <dirent.h> |
07630cea | 23 | #include <errno.h> |
93b0f384 | 24 | #include <fcntl.h> |
07630cea | 25 | #include <linux/sockios.h> |
3e0a2c9a | 26 | #include <net/if.h> |
07630cea LP |
27 | #include <stdbool.h> |
28 | #include <stddef.h> | |
29 | #include <stdio.h> | |
30 | #include <stdlib.h> | |
31 | #include <string.h> | |
3e0a2c9a KS |
32 | #include <sys/ioctl.h> |
33 | #include <sys/socket.h> | |
07630cea LP |
34 | #include <sys/stat.h> |
35 | #include <unistd.h> | |
eb1f0e66 | 36 | |
07630cea | 37 | #include "libudev.h" |
f4ac4d1a | 38 | #include "sd-device.h" |
f4ac4d1a | 39 | |
b5efdb8a | 40 | #include "alloc-util.h" |
07630cea LP |
41 | #include "device-private.h" |
42 | #include "device-util.h" | |
f4ac4d1a | 43 | #include "libudev-device-internal.h" |
07630cea | 44 | #include "libudev-private.h" |
6bedfcbb | 45 | #include "parse-util.h" |
b2661839 | 46 | |
ce1d6d7f KS |
47 | /** |
48 | * SECTION:libudev-device | |
49 | * @short_description: kernel sys devices | |
50 | * | |
51 | * Representation of kernel sys devices. Devices are uniquely identified | |
52 | * by their syspath, every device has exactly one path in the kernel sys | |
5eec7de6 | 53 | * filesystem. Devices usually belong to a kernel subsystem, and have |
214a6c79 | 54 | * a unique name inside that subsystem. |
ce1d6d7f KS |
55 | */ |
56 | ||
905555dc | 57 | /** |
a3321f68 | 58 | * udev_device_get_seqnum: |
905555dc KS |
59 | * @udev_device: udev device |
60 | * | |
61 | * This is only valid if the device was received through a monitor. Devices read from | |
62 | * sys do not have a sequence number. | |
63 | * | |
64 | * Returns: the kernel event sequence number, or 0 if there is no sequence number available. | |
65 | **/ | |
54cf0b7f | 66 | _public_ unsigned long long int udev_device_get_seqnum(struct udev_device *udev_device) |
905555dc | 67 | { |
f4ac4d1a TG |
68 | const char *seqnum; |
69 | unsigned long long ret; | |
70 | int r; | |
905555dc | 71 | |
f4ac4d1a | 72 | assert_return_errno(udev_device, 0, EINVAL); |
905555dc | 73 | |
f4ac4d1a TG |
74 | r = sd_device_get_property_value(udev_device->device, "SEQNUM", &seqnum); |
75 | if (r == -ENOENT) | |
76 | return 0; | |
77 | else if (r < 0) { | |
78 | errno = -r; | |
79 | return 0; | |
80 | } | |
905555dc | 81 | |
f4ac4d1a TG |
82 | r = safe_atollu(seqnum, &ret); |
83 | if (r < 0) { | |
84 | errno = -r; | |
85 | return 0; | |
86 | } | |
905555dc | 87 | |
f4ac4d1a | 88 | return ret; |
905555dc KS |
89 | } |
90 | ||
91 | /** | |
92 | * udev_device_get_devnum: | |
93 | * @udev_device: udev device | |
94 | * | |
21dbe43a KS |
95 | * Get the device major/minor number. |
96 | * | |
97 | * Returns: the dev_t number. | |
905555dc | 98 | **/ |
54cf0b7f | 99 | _public_ dev_t udev_device_get_devnum(struct udev_device *udev_device) |
905555dc | 100 | { |
f4ac4d1a TG |
101 | dev_t devnum; |
102 | int r; | |
905555dc | 103 | |
f4ac4d1a | 104 | assert_return_errno(udev_device, makedev(0, 0), EINVAL); |
905555dc | 105 | |
f4ac4d1a TG |
106 | r = sd_device_get_devnum(udev_device->device, &devnum); |
107 | if (r < 0) { | |
108 | errno = -r; | |
109 | return makedev(0, 0); | |
110 | } | |
905555dc | 111 | |
f4ac4d1a | 112 | return devnum; |
905555dc KS |
113 | } |
114 | ||
115 | /** | |
116 | * udev_device_get_driver: | |
117 | * @udev_device: udev device | |
118 | * | |
21dbe43a KS |
119 | * Get the kernel driver name. |
120 | * | |
121 | * Returns: the driver name string, or #NULL if there is no driver attached. | |
905555dc | 122 | **/ |
54cf0b7f | 123 | _public_ const char *udev_device_get_driver(struct udev_device *udev_device) |
905555dc | 124 | { |
f4ac4d1a TG |
125 | const char *driver; |
126 | int r; | |
127 | ||
128 | assert_return_errno(udev_device, NULL, EINVAL); | |
905555dc | 129 | |
f4ac4d1a TG |
130 | r = sd_device_get_driver(udev_device->device, &driver); |
131 | if (r < 0) { | |
132 | errno = -r; | |
912541b0 | 133 | return NULL; |
912541b0 | 134 | } |
905555dc | 135 | |
f4ac4d1a | 136 | return driver; |
905555dc KS |
137 | } |
138 | ||
139 | /** | |
140 | * udev_device_get_devtype: | |
141 | * @udev_device: udev device | |
142 | * | |
143 | * Retrieve the devtype string of the udev device. | |
144 | * | |
145 | * Returns: the devtype name of the udev device, or #NULL if it can not be determined | |
146 | **/ | |
54cf0b7f | 147 | _public_ const char *udev_device_get_devtype(struct udev_device *udev_device) |
905555dc | 148 | { |
f4ac4d1a TG |
149 | const char *devtype; |
150 | int r; | |
151 | ||
152 | assert_return_errno(udev_device, NULL, EINVAL); | |
153 | ||
154 | r = sd_device_get_devtype(udev_device->device, &devtype); | |
155 | if (r < 0) { | |
156 | errno = -r; | |
912541b0 | 157 | return NULL; |
912541b0 | 158 | } |
905555dc | 159 | |
f4ac4d1a | 160 | return devtype; |
905555dc KS |
161 | } |
162 | ||
163 | /** | |
164 | * udev_device_get_subsystem: | |
165 | * @udev_device: udev device | |
166 | * | |
167 | * Retrieve the subsystem string of the udev device. The string does not | |
168 | * contain any "/". | |
169 | * | |
170 | * Returns: the subsystem name of the udev device, or #NULL if it can not be determined | |
171 | **/ | |
54cf0b7f | 172 | _public_ const char *udev_device_get_subsystem(struct udev_device *udev_device) |
905555dc | 173 | { |
f4ac4d1a TG |
174 | const char *subsystem; |
175 | int r; | |
df546eb5 | 176 | |
f4ac4d1a | 177 | assert_return_errno(udev_device, NULL, EINVAL); |
fc8d61c5 | 178 | |
f4ac4d1a TG |
179 | r = sd_device_get_subsystem(udev_device->device, &subsystem); |
180 | if (r < 0) { | |
181 | errno = -r; | |
912541b0 | 182 | return NULL; |
4189708a TG |
183 | } else if (!subsystem) |
184 | errno = ENODATA; | |
fc8d61c5 | 185 | |
f4ac4d1a | 186 | return subsystem; |
fc8d61c5 KS |
187 | } |
188 | ||
189 | /** | |
190 | * udev_device_get_property_value: | |
191 | * @udev_device: udev device | |
192 | * @key: property name | |
193 | * | |
21dbe43a KS |
194 | * Get the value of a given property. |
195 | * | |
196 | * Returns: the property string, or #NULL if there is no such property. | |
fc8d61c5 | 197 | **/ |
54cf0b7f | 198 | _public_ const char *udev_device_get_property_value(struct udev_device *udev_device, const char *key) |
fc8d61c5 | 199 | { |
f4ac4d1a TG |
200 | const char *value = NULL; |
201 | int r; | |
912541b0 | 202 | |
f4ac4d1a | 203 | assert_return_errno(udev_device && key, NULL, EINVAL); |
912541b0 | 204 | |
f4ac4d1a TG |
205 | r = sd_device_get_property_value(udev_device->device, key, &value); |
206 | if (r < 0) { | |
207 | errno = -r; | |
208 | return NULL; | |
912541b0 KS |
209 | } |
210 | ||
f4ac4d1a | 211 | return value; |
99214844 KS |
212 | } |
213 | ||
f4ac4d1a | 214 | struct udev_device *udev_device_new(struct udev *udev) { |
912541b0 | 215 | struct udev_device *udev_device; |
912541b0 | 216 | |
f4ac4d1a | 217 | assert_return_errno(udev, NULL, EINVAL); |
912541b0 | 218 | |
955d98c9 | 219 | udev_device = new0(struct udev_device, 1); |
f4ac4d1a | 220 | if (!udev_device) { |
aa0e72ea | 221 | errno = ENOMEM; |
912541b0 | 222 | return NULL; |
aa0e72ea | 223 | } |
912541b0 KS |
224 | udev_device->refcount = 1; |
225 | udev_device->udev = udev; | |
f4ac4d1a TG |
226 | udev_list_init(udev, &udev_device->properties, true); |
227 | udev_list_init(udev, &udev_device->tags, true); | |
228 | udev_list_init(udev, &udev_device->sysattrs, true); | |
229 | udev_list_init(udev, &udev_device->devlinks, true); | |
41b848b0 | 230 | |
912541b0 | 231 | return udev_device; |
eb1f0e66 KS |
232 | } |
233 | ||
234 | /** | |
8753fadf | 235 | * udev_device_new_from_syspath: |
eb1f0e66 | 236 | * @udev: udev library context |
8753fadf | 237 | * @syspath: sys device path including sys directory |
eb1f0e66 | 238 | * |
8753fadf | 239 | * Create new udev device, and fill in information from the sys |
214a6c79 | 240 | * device and the udev database entry. The syspath is the absolute |
8753fadf | 241 | * path to the device, including the sys mount point. |
eb1f0e66 KS |
242 | * |
243 | * The initial refcount is 1, and needs to be decremented to | |
be7de409 | 244 | * release the resources of the udev device. |
eb1f0e66 KS |
245 | * |
246 | * Returns: a new udev device, or #NULL, if it does not exist | |
247 | **/ | |
f4ac4d1a | 248 | _public_ struct udev_device *udev_device_new_from_syspath(struct udev *udev, const char *syspath) { |
912541b0 | 249 | struct udev_device *udev_device; |
f4ac4d1a | 250 | int r; |
912541b0 | 251 | |
f4ac4d1a TG |
252 | udev_device = udev_device_new(udev); |
253 | if (!udev_device) | |
912541b0 | 254 | return NULL; |
912541b0 | 255 | |
f4ac4d1a TG |
256 | r = sd_device_new_from_syspath(&udev_device->device, syspath); |
257 | if (r < 0) { | |
258 | errno = -r; | |
259 | udev_device_unref(udev_device); | |
912541b0 | 260 | return NULL; |
aa0e72ea | 261 | } |
912541b0 | 262 | |
912541b0 | 263 | return udev_device; |
eb1f0e66 KS |
264 | } |
265 | ||
1e511322 KS |
266 | /** |
267 | * udev_device_new_from_devnum: | |
268 | * @udev: udev library context | |
269 | * @type: char or block device | |
270 | * @devnum: device major/minor number | |
271 | * | |
272 | * Create new udev device, and fill in information from the sys | |
dbba7e40 KS |
273 | * device and the udev database entry. The device is looked-up |
274 | * by its major/minor number and type. Character and block device | |
275 | * numbers are not unique across the two types. | |
1e511322 KS |
276 | * |
277 | * The initial refcount is 1, and needs to be decremented to | |
278 | * release the resources of the udev device. | |
279 | * | |
280 | * Returns: a new udev device, or #NULL, if it does not exist | |
281 | **/ | |
54cf0b7f | 282 | _public_ struct udev_device *udev_device_new_from_devnum(struct udev *udev, char type, dev_t devnum) |
4c9dff47 | 283 | { |
f4ac4d1a TG |
284 | struct udev_device *udev_device; |
285 | int r; | |
286 | ||
287 | udev_device = udev_device_new(udev); | |
288 | if (!udev_device) | |
289 | return NULL; | |
290 | ||
291 | r = sd_device_new_from_devnum(&udev_device->device, type, devnum); | |
292 | if (r < 0) { | |
293 | errno = -r; | |
294 | udev_device_unref(udev_device); | |
912541b0 | 295 | return NULL; |
aa0e72ea | 296 | } |
4c9dff47 | 297 | |
f4ac4d1a | 298 | return udev_device; |
4c9dff47 KS |
299 | } |
300 | ||
dbf61afb KS |
301 | /** |
302 | * udev_device_new_from_device_id: | |
303 | * @udev: udev library context | |
304 | * @id: text string identifying a kernel device | |
305 | * | |
306 | * Create new udev device, and fill in information from the sys | |
307 | * device and the udev database entry. The device is looked-up | |
308 | * by a special string: | |
309 | * b8:2 - block device major:minor | |
310 | * c128:1 - char device major:minor | |
311 | * n3 - network device ifindex | |
312 | * +sound:card29 - kernel driver core subsystem:device name | |
313 | * | |
314 | * The initial refcount is 1, and needs to be decremented to | |
315 | * release the resources of the udev device. | |
316 | * | |
317 | * Returns: a new udev device, or #NULL, if it does not exist | |
318 | **/ | |
67410e9f | 319 | _public_ struct udev_device *udev_device_new_from_device_id(struct udev *udev, const char *id) |
cad40a5f | 320 | { |
f4ac4d1a TG |
321 | struct udev_device *udev_device; |
322 | int r; | |
323 | ||
324 | udev_device = udev_device_new(udev); | |
325 | if (!udev_device) | |
912541b0 | 326 | return NULL; |
f4ac4d1a TG |
327 | |
328 | r = sd_device_new_from_device_id(&udev_device->device, id); | |
329 | if (r < 0) { | |
330 | errno = -r; | |
331 | udev_device_unref(udev_device); | |
912541b0 KS |
332 | return NULL; |
333 | } | |
f4ac4d1a TG |
334 | |
335 | return udev_device; | |
cad40a5f KS |
336 | } |
337 | ||
1e511322 KS |
338 | /** |
339 | * udev_device_new_from_subsystem_sysname: | |
340 | * @udev: udev library context | |
214a6c79 | 341 | * @subsystem: the subsystem of the device |
1e511322 KS |
342 | * @sysname: the name of the device |
343 | * | |
dbba7e40 KS |
344 | * Create new udev device, and fill in information from the sys device |
345 | * and the udev database entry. The device is looked up by the subsystem | |
346 | * and name string of the device, like "mem" / "zero", or "block" / "sda". | |
1e511322 KS |
347 | * |
348 | * The initial refcount is 1, and needs to be decremented to | |
349 | * release the resources of the udev device. | |
350 | * | |
351 | * Returns: a new udev device, or #NULL, if it does not exist | |
352 | **/ | |
54cf0b7f | 353 | _public_ struct udev_device *udev_device_new_from_subsystem_sysname(struct udev *udev, const char *subsystem, const char *sysname) |
90d80c2e | 354 | { |
f4ac4d1a TG |
355 | struct udev_device *udev_device; |
356 | int r; | |
912541b0 | 357 | |
f4ac4d1a TG |
358 | udev_device = udev_device_new(udev); |
359 | if (!udev_device) | |
360 | return NULL; | |
aa0e72ea | 361 | |
f4ac4d1a TG |
362 | r = sd_device_new_from_subsystem_sysname(&udev_device->device, subsystem, sysname); |
363 | if (r < 0) { | |
364 | errno = -r; | |
365 | udev_device_unref(udev_device); | |
366 | return NULL; | |
912541b0 KS |
367 | } |
368 | ||
f4ac4d1a | 369 | return udev_device; |
90d80c2e KS |
370 | } |
371 | ||
fc8d61c5 KS |
372 | /** |
373 | * udev_device_new_from_environment | |
374 | * @udev: udev library context | |
375 | * | |
376 | * Create new udev device, and fill in information from the | |
377 | * current process environment. This only works reliable if | |
378 | * the process is called from a udev rule. It is usually used | |
379 | * for tools executed from IMPORT= rules. | |
380 | * | |
381 | * The initial refcount is 1, and needs to be decremented to | |
382 | * release the resources of the udev device. | |
383 | * | |
384 | * Returns: a new udev device, or #NULL, if it does not exist | |
385 | **/ | |
54cf0b7f | 386 | _public_ struct udev_device *udev_device_new_from_environment(struct udev *udev) |
fc8d61c5 | 387 | { |
912541b0 | 388 | struct udev_device *udev_device; |
f4ac4d1a | 389 | int r; |
fc8d61c5 | 390 | |
912541b0 | 391 | udev_device = udev_device_new(udev); |
f4ac4d1a | 392 | if (!udev_device) |
912541b0 | 393 | return NULL; |
fc8d61c5 | 394 | |
f4ac4d1a TG |
395 | r = device_new_from_strv(&udev_device->device, environ); |
396 | if (r < 0) { | |
397 | errno = -r; | |
912541b0 | 398 | udev_device_unref(udev_device); |
f4ac4d1a | 399 | return NULL; |
912541b0 | 400 | } |
fc8d61c5 | 401 | |
912541b0 | 402 | return udev_device; |
fc8d61c5 KS |
403 | } |
404 | ||
f4ac4d1a | 405 | static struct udev_device *device_new_from_parent(struct udev_device *child) |
4ad3a37f | 406 | { |
f4ac4d1a TG |
407 | struct udev_device *parent; |
408 | int r; | |
409 | ||
410 | assert_return_errno(child, NULL, EINVAL); | |
411 | ||
412 | parent = udev_device_new(child->udev); | |
413 | if (!parent) | |
414 | return NULL; | |
415 | ||
416 | r = sd_device_get_parent(child->device, &parent->device); | |
417 | if (r < 0) { | |
418 | errno = -r; | |
419 | udev_device_unref(parent); | |
420 | return NULL; | |
912541b0 | 421 | } |
aa0e72ea | 422 | |
f4ac4d1a TG |
423 | /* the parent is unref'ed with the child, so take a ref from libudev as well */ |
424 | sd_device_ref(parent->device); | |
425 | ||
426 | return parent; | |
4ad3a37f KS |
427 | } |
428 | ||
1e511322 KS |
429 | /** |
430 | * udev_device_get_parent: | |
431 | * @udev_device: the device to start searching from | |
432 | * | |
433 | * Find the next parent device, and fill in information from the sys | |
434 | * device and the udev database entry. | |
435 | * | |
572ce4f7 ZJS |
436 | * Returned device is not referenced. It is attached to the child |
437 | * device, and will be cleaned up when the child device is cleaned up. | |
1e511322 | 438 | * |
214a6c79 | 439 | * It is not necessarily just the upper level directory, empty or not |
1e511322 KS |
440 | * recognized sys directories are ignored. |
441 | * | |
442 | * It can be called as many times as needed, without caring about | |
443 | * references. | |
444 | * | |
445 | * Returns: a new udev device, or #NULL, if it no parent exist. | |
446 | **/ | |
54cf0b7f | 447 | _public_ struct udev_device *udev_device_get_parent(struct udev_device *udev_device) |
b2d9e4f2 | 448 | { |
f4ac4d1a TG |
449 | assert_return_errno(udev_device, NULL, EINVAL); |
450 | ||
912541b0 KS |
451 | if (!udev_device->parent_set) { |
452 | udev_device->parent_set = true; | |
f4ac4d1a | 453 | udev_device->parent = device_new_from_parent(udev_device); |
912541b0 | 454 | } |
f4ac4d1a TG |
455 | |
456 | /* TODO: errno will differ here in case parent == NULL */ | |
457 | return udev_device->parent; | |
b2d9e4f2 KS |
458 | } |
459 | ||
1e511322 KS |
460 | /** |
461 | * udev_device_get_parent_with_subsystem_devtype: | |
462 | * @udev_device: udev device to start searching from | |
214a6c79 | 463 | * @subsystem: the subsystem of the device |
1e511322 KS |
464 | * @devtype: the type (DEVTYPE) of the device |
465 | * | |
466 | * Find the next parent device, with a matching subsystem and devtype | |
467 | * value, and fill in information from the sys device and the udev | |
468 | * database entry. | |
469 | * | |
79ef2e97 | 470 | * If devtype is #NULL, only subsystem is checked, and any devtype will |
54d4f54e MP |
471 | * match. |
472 | * | |
572ce4f7 ZJS |
473 | * Returned device is not referenced. It is attached to the child |
474 | * device, and will be cleaned up when the child device is cleaned up. | |
1e511322 KS |
475 | * |
476 | * It can be called as many times as needed, without caring about | |
477 | * references. | |
478 | * | |
8d6bc73a | 479 | * Returns: a new udev device, or #NULL if no matching parent exists. |
1e511322 | 480 | **/ |
54cf0b7f | 481 | _public_ struct udev_device *udev_device_get_parent_with_subsystem_devtype(struct udev_device *udev_device, const char *subsystem, const char *devtype) |
bf8b2ae1 | 482 | { |
f4ac4d1a TG |
483 | sd_device *parent; |
484 | int r; | |
bf8b2ae1 | 485 | |
f4ac4d1a TG |
486 | assert_return_errno(udev_device, NULL, EINVAL); |
487 | ||
488 | /* this relies on the fact that finding the subdevice of a parent or the | |
489 | parent of a subdevice commute */ | |
490 | ||
491 | /* first find the correct sd_device */ | |
492 | r = sd_device_get_parent_with_subsystem_devtype(udev_device->device, subsystem, devtype, &parent); | |
493 | if (r < 0) { | |
494 | errno = -r; | |
912541b0 | 495 | return NULL; |
aa0e72ea | 496 | } |
883012d4 | 497 | |
f4ac4d1a TG |
498 | /* then walk the chain of udev_device parents until the correspanding |
499 | one is found */ | |
500 | while ((udev_device = udev_device_get_parent(udev_device))) { | |
501 | if (udev_device->device == parent) | |
502 | return udev_device; | |
912541b0 | 503 | } |
aa0e72ea | 504 | |
f4ac4d1a TG |
505 | errno = ENOENT; |
506 | return NULL; | |
bf8b2ae1 MH |
507 | } |
508 | ||
eb1f0e66 KS |
509 | /** |
510 | * udev_device_get_udev: | |
7d8787b3 | 511 | * @udev_device: udev device |
eb1f0e66 KS |
512 | * |
513 | * Retrieve the udev library context the device was created with. | |
514 | * | |
515 | * Returns: the udev library context | |
516 | **/ | |
54cf0b7f | 517 | _public_ struct udev *udev_device_get_udev(struct udev_device *udev_device) |
eb1f0e66 | 518 | { |
f4ac4d1a TG |
519 | assert_return_errno(udev_device, NULL, EINVAL); |
520 | ||
912541b0 | 521 | return udev_device->udev; |
eb1f0e66 KS |
522 | } |
523 | ||
524 | /** | |
525 | * udev_device_ref: | |
526 | * @udev_device: udev device | |
527 | * | |
528 | * Take a reference of a udev device. | |
529 | * | |
530 | * Returns: the passed udev device | |
531 | **/ | |
54cf0b7f | 532 | _public_ struct udev_device *udev_device_ref(struct udev_device *udev_device) |
eb1f0e66 | 533 | { |
f4ac4d1a TG |
534 | if (udev_device) |
535 | udev_device->refcount++; | |
536 | ||
912541b0 | 537 | return udev_device; |
eb1f0e66 KS |
538 | } |
539 | ||
540 | /** | |
541 | * udev_device_unref: | |
542 | * @udev_device: udev device | |
543 | * | |
544 | * Drop a reference of a udev device. If the refcount reaches zero, | |
be7de409 | 545 | * the resources of the device will be released. |
eb1f0e66 | 546 | * |
725d7e6c | 547 | * Returns: #NULL |
eb1f0e66 | 548 | **/ |
20bbd54f | 549 | _public_ struct udev_device *udev_device_unref(struct udev_device *udev_device) |
eb1f0e66 | 550 | { |
f4ac4d1a TG |
551 | if (udev_device && (-- udev_device->refcount) == 0) { |
552 | sd_device_unref(udev_device->device); | |
553 | udev_device_unref(udev_device->parent); | |
554 | ||
555 | udev_list_cleanup(&udev_device->properties); | |
556 | udev_list_cleanup(&udev_device->sysattrs); | |
557 | udev_list_cleanup(&udev_device->tags); | |
558 | udev_list_cleanup(&udev_device->devlinks); | |
559 | ||
560 | free(udev_device); | |
561 | } | |
562 | ||
20bbd54f | 563 | return NULL; |
eb1f0e66 KS |
564 | } |
565 | ||
566 | /** | |
567 | * udev_device_get_devpath: | |
568 | * @udev_device: udev device | |
569 | * | |
11d543c1 KS |
570 | * Retrieve the kernel devpath value of the udev device. The path |
571 | * does not contain the sys mount point, and starts with a '/'. | |
eb1f0e66 | 572 | * |
11d543c1 | 573 | * Returns: the devpath of the udev device |
eb1f0e66 | 574 | **/ |
54cf0b7f | 575 | _public_ const char *udev_device_get_devpath(struct udev_device *udev_device) |
eb1f0e66 | 576 | { |
f4ac4d1a TG |
577 | const char *devpath; |
578 | int r; | |
579 | ||
580 | assert_return_errno(udev_device, NULL, EINVAL); | |
581 | ||
582 | r = sd_device_get_devpath(udev_device->device, &devpath); | |
583 | if (r < 0) { | |
584 | errno = -r; | |
912541b0 | 585 | return NULL; |
f4ac4d1a TG |
586 | } |
587 | ||
588 | return devpath; | |
eb1f0e66 KS |
589 | } |
590 | ||
11d543c1 KS |
591 | /** |
592 | * udev_device_get_syspath: | |
593 | * @udev_device: udev device | |
594 | * | |
595 | * Retrieve the sys path of the udev device. The path is an | |
596 | * absolute path and starts with the sys mount point. | |
597 | * | |
598 | * Returns: the sys path of the udev device | |
599 | **/ | |
54cf0b7f | 600 | _public_ const char *udev_device_get_syspath(struct udev_device *udev_device) |
11d543c1 | 601 | { |
f4ac4d1a TG |
602 | const char *syspath; |
603 | int r; | |
604 | ||
605 | assert_return_errno(udev_device, NULL, EINVAL); | |
606 | ||
607 | r = sd_device_get_syspath(udev_device->device, &syspath); | |
608 | if (r < 0) { | |
609 | errno = -r; | |
912541b0 | 610 | return NULL; |
f4ac4d1a TG |
611 | } |
612 | ||
613 | return syspath; | |
11d543c1 KS |
614 | } |
615 | ||
1e511322 KS |
616 | /** |
617 | * udev_device_get_sysname: | |
618 | * @udev_device: udev device | |
619 | * | |
21dbe43a KS |
620 | * Get the kernel device name in /sys. |
621 | * | |
622 | * Returns: the name string of the device device | |
1e511322 | 623 | **/ |
54cf0b7f | 624 | _public_ const char *udev_device_get_sysname(struct udev_device *udev_device) |
4ad3a37f | 625 | { |
f4ac4d1a TG |
626 | const char *sysname; |
627 | int r; | |
628 | ||
629 | assert_return_errno(udev_device, NULL, EINVAL); | |
630 | ||
631 | r = sd_device_get_sysname(udev_device->device, &sysname); | |
632 | if (r < 0) { | |
633 | errno = -r; | |
912541b0 | 634 | return NULL; |
f4ac4d1a TG |
635 | } |
636 | ||
637 | return sysname; | |
4ad3a37f KS |
638 | } |
639 | ||
1e511322 KS |
640 | /** |
641 | * udev_device_get_sysnum: | |
642 | * @udev_device: udev device | |
643 | * | |
21dbe43a KS |
644 | * Get the instance number of the device. |
645 | * | |
c5315881 | 646 | * Returns: the trailing number string of the device name |
1e511322 | 647 | **/ |
54cf0b7f | 648 | _public_ const char *udev_device_get_sysnum(struct udev_device *udev_device) |
517814e7 | 649 | { |
f4ac4d1a TG |
650 | const char *sysnum; |
651 | int r; | |
652 | ||
653 | assert_return_errno(udev_device, NULL, EINVAL); | |
654 | ||
655 | r = sd_device_get_sysnum(udev_device->device, &sysnum); | |
656 | if (r < 0) { | |
657 | errno = -r; | |
912541b0 | 658 | return NULL; |
f4ac4d1a TG |
659 | } |
660 | ||
661 | return sysnum; | |
517814e7 KS |
662 | } |
663 | ||
eb1f0e66 | 664 | /** |
fb762bb9 | 665 | * udev_device_get_devnode: |
eb1f0e66 KS |
666 | * @udev_device: udev device |
667 | * | |
668 | * Retrieve the device node file name belonging to the udev device. | |
ba6929f6 | 669 | * The path is an absolute path, and starts with the device directory. |
eb1f0e66 KS |
670 | * |
671 | * Returns: the device node file name of the udev device, or #NULL if no device node exists | |
672 | **/ | |
54cf0b7f | 673 | _public_ const char *udev_device_get_devnode(struct udev_device *udev_device) |
eb1f0e66 | 674 | { |
f4ac4d1a TG |
675 | const char *devnode; |
676 | int r; | |
677 | ||
678 | assert_return_errno(udev_device, NULL, EINVAL); | |
679 | ||
680 | r = sd_device_get_devname(udev_device->device, &devnode); | |
681 | if (r < 0) { | |
682 | errno = -r; | |
912541b0 | 683 | return NULL; |
f4ac4d1a TG |
684 | } |
685 | ||
686 | return devnode; | |
eb1f0e66 KS |
687 | } |
688 | ||
eb1f0e66 | 689 | /** |
0de33a61 | 690 | * udev_device_get_devlinks_list_entry: |
eb1f0e66 | 691 | * @udev_device: udev device |
eb1f0e66 | 692 | * |
bf7ad0ea KS |
693 | * Retrieve the list of device links pointing to the device file of |
694 | * the udev device. The next list entry can be retrieved with | |
bb061708 | 695 | * udev_list_entry_get_next(), which returns #NULL if no more entries exist. |
bf7ad0ea | 696 | * The devlink path can be retrieved from the list entry by |
e345e267 | 697 | * udev_list_entry_get_name(). The path is an absolute path, and starts with |
bf7ad0ea | 698 | * the device directory. |
eb1f0e66 | 699 | * |
bf7ad0ea | 700 | * Returns: the first entry of the device node link list |
eb1f0e66 | 701 | **/ |
54cf0b7f | 702 | _public_ struct udev_list_entry *udev_device_get_devlinks_list_entry(struct udev_device *udev_device) |
eb1f0e66 | 703 | { |
f4ac4d1a | 704 | assert_return_errno(udev_device, NULL, EINVAL); |
eb1f0e66 | 705 | |
378f61eb TG |
706 | if (device_get_devlinks_generation(udev_device->device) != udev_device->devlinks_generation || |
707 | !udev_device->devlinks_read) { | |
f4ac4d1a TG |
708 | const char *devlink; |
709 | ||
710 | udev_list_cleanup(&udev_device->devlinks); | |
711 | ||
712 | FOREACH_DEVICE_DEVLINK(udev_device->device, devlink) | |
713 | udev_list_entry_add(&udev_device->devlinks, devlink, NULL); | |
714 | ||
378f61eb | 715 | udev_device->devlinks_read = true; |
f4ac4d1a TG |
716 | udev_device->devlinks_generation = device_get_devlinks_generation(udev_device->device); |
717 | } | |
718 | ||
719 | return udev_list_get_entry(&udev_device->devlinks); | |
979ff016 KS |
720 | } |
721 | ||
eb1f0e66 | 722 | /** |
f4ac4d1a | 723 | * udev_device_get_event_properties_entry: |
eb1f0e66 | 724 | * @udev_device: udev device |
eb1f0e66 | 725 | * |
bf7ad0ea | 726 | * Retrieve the list of key/value device properties of the udev |
bb061708 | 727 | * device. The next list entry can be retrieved with udev_list_entry_get_next(), |
bf7ad0ea | 728 | * which returns #NULL if no more entries exist. The property name |
bb061708 KS |
729 | * can be retrieved from the list entry by udev_list_entry_get_name(), |
730 | * the property value by udev_list_entry_get_value(). | |
eb1f0e66 | 731 | * |
bf7ad0ea | 732 | * Returns: the first entry of the property list |
eb1f0e66 | 733 | **/ |
54cf0b7f | 734 | _public_ struct udev_list_entry *udev_device_get_properties_list_entry(struct udev_device *udev_device) |
eb1f0e66 | 735 | { |
f4ac4d1a TG |
736 | assert_return_errno(udev_device, NULL, EINVAL); |
737 | ||
378f61eb TG |
738 | if (device_get_properties_generation(udev_device->device) != udev_device->properties_generation || |
739 | !udev_device->properties_read) { | |
f4ac4d1a TG |
740 | const char *key, *value; |
741 | ||
742 | udev_list_cleanup(&udev_device->properties); | |
743 | ||
744 | FOREACH_DEVICE_PROPERTY(udev_device->device, key, value) | |
745 | udev_list_entry_add(&udev_device->properties, key, value); | |
746 | ||
378f61eb | 747 | udev_device->properties_read = true; |
f4ac4d1a | 748 | udev_device->properties_generation = device_get_properties_generation(udev_device->device); |
912541b0 | 749 | } |
f4ac4d1a TG |
750 | |
751 | return udev_list_get_entry(&udev_device->properties); | |
eb1f0e66 | 752 | } |
11d543c1 | 753 | |
1e511322 KS |
754 | /** |
755 | * udev_device_get_action: | |
756 | * @udev_device: udev device | |
757 | * | |
758 | * This is only valid if the device was received through a monitor. Devices read from | |
759 | * sys do not have an action string. Usual actions are: add, remove, change, online, | |
760 | * offline. | |
761 | * | |
762 | * Returns: the kernel action value, or #NULL if there is no action value available. | |
763 | **/ | |
f4ac4d1a TG |
764 | _public_ const char *udev_device_get_action(struct udev_device *udev_device) { |
765 | const char *action = NULL; | |
766 | int r; | |
767 | ||
768 | assert_return_errno(udev_device, NULL, EINVAL); | |
769 | ||
770 | r = sd_device_get_property_value(udev_device->device, "ACTION", &action); | |
771 | if (r < 0 && r != -ENOENT) { | |
772 | errno = -r; | |
912541b0 | 773 | return NULL; |
f4ac4d1a TG |
774 | } |
775 | ||
776 | return action; | |
c4f5f942 KS |
777 | } |
778 | ||
9c6a11b1 KS |
779 | /** |
780 | * udev_device_get_usec_since_initialized: | |
781 | * @udev_device: udev device | |
782 | * | |
783 | * Return the number of microseconds passed since udev set up the | |
784 | * device for the first time. | |
785 | * | |
786 | * This is only implemented for devices with need to store properties | |
787 | * in the udev database. All other devices return 0 here. | |
788 | * | |
789 | * Returns: the number of microseconds since the device was first seen. | |
790 | **/ | |
54cf0b7f | 791 | _public_ unsigned long long int udev_device_get_usec_since_initialized(struct udev_device *udev_device) |
9c6a11b1 | 792 | { |
f4ac4d1a TG |
793 | usec_t ts; |
794 | int r; | |
9c6a11b1 | 795 | |
f4ac4d1a TG |
796 | assert_return(udev_device, -EINVAL); |
797 | ||
798 | r = sd_device_get_usec_since_initialized(udev_device->device, &ts); | |
799 | if (r < 0) { | |
800 | errno = EINVAL; | |
912541b0 | 801 | return 0; |
f4ac4d1a | 802 | } |
9c6a11b1 | 803 | |
f4ac4d1a | 804 | return ts; |
9c6a11b1 KS |
805 | } |
806 | ||
1e511322 KS |
807 | /** |
808 | * udev_device_get_sysattr_value: | |
809 | * @udev_device: udev device | |
810 | * @sysattr: attribute name | |
811 | * | |
456719b6 | 812 | * The retrieved value is cached in the device. Repeated calls will return the same |
1e511322 KS |
813 | * value and not open the attribute again. |
814 | * | |
815 | * Returns: the content of a sys attribute file, or #NULL if there is no sys attribute value. | |
816 | **/ | |
54cf0b7f | 817 | _public_ const char *udev_device_get_sysattr_value(struct udev_device *udev_device, const char *sysattr) |
93b0f384 | 818 | { |
f4ac4d1a TG |
819 | const char *value; |
820 | int r; | |
912541b0 | 821 | |
f4ac4d1a | 822 | assert_return_errno(udev_device, NULL, EINVAL); |
912541b0 | 823 | |
f4ac4d1a TG |
824 | r = sd_device_get_sysattr_value(udev_device->device, sysattr, &value); |
825 | if (r < 0) { | |
826 | errno = -r; | |
827 | return NULL; | |
912541b0 KS |
828 | } |
829 | ||
f4ac4d1a | 830 | return value; |
93b0f384 | 831 | } |
517814e7 | 832 | |
946f1825 HR |
833 | /** |
834 | * udev_device_set_sysattr_value: | |
835 | * @udev_device: udev device | |
836 | * @sysattr: attribute name | |
837 | * @value: new value to be set | |
838 | * | |
839 | * Update the contents of the sys attribute and the cached value of the device. | |
840 | * | |
841 | * Returns: Negative error code on failure or 0 on success. | |
842 | **/ | |
843 | _public_ int udev_device_set_sysattr_value(struct udev_device *udev_device, const char *sysattr, char *value) | |
844 | { | |
f4ac4d1a | 845 | int r; |
f180ad25 | 846 | |
f4ac4d1a | 847 | assert_return(udev_device, -EINVAL); |
f180ad25 | 848 | |
f4ac4d1a TG |
849 | r = sd_device_set_sysattr_value(udev_device->device, sysattr, value); |
850 | if (r < 0) | |
851 | return r; | |
f180ad25 | 852 | |
f4ac4d1a | 853 | return 0; |
f180ad25 TE |
854 | } |
855 | ||
856 | /** | |
857 | * udev_device_get_sysattr_list_entry: | |
858 | * @udev_device: udev device | |
859 | * | |
860 | * Retrieve the list of available sysattrs, with value being empty; | |
20bee04c KS |
861 | * This just return all available sysfs attributes for a particular |
862 | * device without reading their values. | |
f180ad25 TE |
863 | * |
864 | * Returns: the first entry of the property list | |
865 | **/ | |
54cf0b7f | 866 | _public_ struct udev_list_entry *udev_device_get_sysattr_list_entry(struct udev_device *udev_device) |
f180ad25 | 867 | { |
f4ac4d1a | 868 | assert_return_errno(udev_device, NULL, EINVAL); |
f180ad25 | 869 | |
f4ac4d1a TG |
870 | if (!udev_device->sysattrs_read) { |
871 | const char *sysattr; | |
f180ad25 | 872 | |
f4ac4d1a | 873 | udev_list_cleanup(&udev_device->sysattrs); |
11d543c1 | 874 | |
f4ac4d1a | 875 | FOREACH_DEVICE_SYSATTR(udev_device->device, sysattr) |
7bb09214 | 876 | udev_list_entry_add(&udev_device->sysattrs, sysattr, NULL); |
11d543c1 | 877 | |
f4ac4d1a | 878 | udev_device->sysattrs_read = true; |
912541b0 | 879 | } |
f4ac4d1a TG |
880 | |
881 | return udev_list_get_entry(&udev_device->sysattrs); | |
4281da1f KS |
882 | } |
883 | ||
48a0170b KS |
884 | /** |
885 | * udev_device_get_is_initialized: | |
886 | * @udev_device: udev device | |
887 | * | |
888 | * Check if udev has already handled the device and has set up | |
889 | * device node permissions and context, or has renamed a network | |
890 | * device. | |
891 | * | |
9c6a11b1 | 892 | * This is only implemented for devices with a device node |
48a0170b KS |
893 | * or network interfaces. All other devices return 1 here. |
894 | * | |
895 | * Returns: 1 if the device is set up. 0 otherwise. | |
896 | **/ | |
54cf0b7f | 897 | _public_ int udev_device_get_is_initialized(struct udev_device *udev_device) |
48a0170b | 898 | { |
f4ac4d1a | 899 | int r, initialized; |
48a0170b | 900 | |
f4ac4d1a | 901 | assert_return(udev_device, -EINVAL); |
48a0170b | 902 | |
f4ac4d1a TG |
903 | r = sd_device_get_is_initialized(udev_device->device, &initialized); |
904 | if (r < 0) { | |
905 | errno = -r; | |
8e3ba377 | 906 | |
912541b0 | 907 | return 0; |
8e3ba377 | 908 | } |
8e3ba377 | 909 | |
f4ac4d1a | 910 | return initialized; |
28460195 KS |
911 | } |
912 | ||
f712894d KS |
913 | /** |
914 | * udev_device_get_tags_list_entry: | |
915 | * @udev_device: udev device | |
916 | * | |
917 | * Retrieve the list of tags attached to the udev device. The next | |
bb061708 | 918 | * list entry can be retrieved with udev_list_entry_get_next(), |
f712894d | 919 | * which returns #NULL if no more entries exist. The tag string |
bb061708 | 920 | * can be retrieved from the list entry by udev_list_entry_get_name(). |
f712894d KS |
921 | * |
922 | * Returns: the first entry of the tag list | |
923 | **/ | |
54cf0b7f | 924 | _public_ struct udev_list_entry *udev_device_get_tags_list_entry(struct udev_device *udev_device) |
28460195 | 925 | { |
f4ac4d1a TG |
926 | assert_return_errno(udev_device, NULL, EINVAL); |
927 | ||
378f61eb TG |
928 | if (device_get_tags_generation(udev_device->device) != udev_device->tags_generation || |
929 | !udev_device->tags_read) { | |
f4ac4d1a TG |
930 | const char *tag; |
931 | ||
932 | udev_list_cleanup(&udev_device->tags); | |
933 | ||
934 | FOREACH_DEVICE_TAG(udev_device->device, tag) | |
935 | udev_list_entry_add(&udev_device->tags, tag, NULL); | |
936 | ||
378f61eb | 937 | udev_device->tags_read = true; |
f4ac4d1a TG |
938 | udev_device->tags_generation = device_get_tags_generation(udev_device->device); |
939 | } | |
940 | ||
941 | return udev_list_get_entry(&udev_device->tags); | |
28460195 KS |
942 | } |
943 | ||
21dbe43a KS |
944 | /** |
945 | * udev_device_has_tag: | |
946 | * @udev_device: udev device | |
947 | * @tag: tag name | |
948 | * | |
949 | * Check if a given device has a certain tag associated. | |
950 | * | |
951 | * Returns: 1 if the tag is found. 0 otherwise. | |
952 | **/ | |
54cf0b7f | 953 | _public_ int udev_device_has_tag(struct udev_device *udev_device, const char *tag) |
28460195 | 954 | { |
f4ac4d1a | 955 | assert_return(udev_device, 0); |
fa639f3a | 956 | |
f4ac4d1a | 957 | return sd_device_has_tag(udev_device->device, tag); |
1cd0a770 | 958 | } |