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