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