]> git.ipfire.org Git - thirdparty/systemd.git/blame - libudev/libudev-device.c
Merge branch 'firmware' of git://git.kernel.org/pub/scm/linux/kernel/git/jcm/udev-jcm
[thirdparty/systemd.git] / libudev / libudev-device.c
CommitLineData
eb1f0e66
KS
1/*
2 * libudev - interface to udev device information
3 *
065db052 4 * Copyright (C) 2008-2009 Kay Sievers <kay.sievers@vrfy.org>
eb1f0e66 5 *
4061ab9f
KS
6 * This library is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU Lesser General Public
8 * License as published by the Free Software Foundation; either
9 * version 2.1 of the License, or (at your option) any later version.
eb1f0e66
KS
10 */
11
eb1f0e66
KS
12#include <stdio.h>
13#include <stdlib.h>
14#include <stddef.h>
15#include <unistd.h>
16#include <errno.h>
17#include <string.h>
18#include <dirent.h>
93b0f384 19#include <fcntl.h>
517814e7 20#include <ctype.h>
eb1f0e66
KS
21#include <sys/stat.h>
22
23#include "libudev.h"
24#include "libudev-private.h"
eb1f0e66 25
ce1d6d7f
KS
26/**
27 * SECTION:libudev-device
28 * @short_description: kernel sys devices
29 *
30 * Representation of kernel sys devices. Devices are uniquely identified
31 * by their syspath, every device has exactly one path in the kernel sys
32 * filesystem. Devices usually belong to a kernel subsystem, and and have
33 * a unique name inside that subsytem.
34 */
35
1e511322
KS
36/**
37 * udev_device:
38 *
ce1d6d7f 39 * Opaque object representing one kernel sys device.
1e511322 40 */
11d543c1 41struct udev_device {
11d543c1 42 struct udev *udev;
b2d9e4f2 43 struct udev_device *parent_device;
11d543c1 44 char *syspath;
4ad3a37f 45 const char *devpath;
517814e7
KS
46 char *sysname;
47 const char *sysnum;
99214844 48 char *devnode;
11d543c1 49 char *subsystem;
bf8b2ae1 50 char *devtype;
979ff016 51 char *driver;
c4f5f942 52 char *action;
c4f5f942 53 char *devpath_old;
cb14f454 54 char *knodename;
6493e655 55 char **envp;
c2654402
KS
56 char *monitor_buf;
57 size_t monitor_buf_len;
b99028c9
KS
58 struct udev_list_node devlinks_list;
59 struct udev_list_node properties_list;
60 struct udev_list_node sysattr_list;
6bd1c78a 61 unsigned long long int seqnum;
b99028c9
KS
62 int event_timeout;
63 int timeout;
6bd1c78a 64 int num_fake_partitions;
e88a82b5 65 int devlink_priority;
b99028c9
KS
66 int refcount;
67 dev_t devnum;
d7ce7539 68 int watch_handle;
b99028c9
KS
69 unsigned int parent_set:1;
70 unsigned int subsystem_set:1;
bf8b2ae1 71 unsigned int devtype_set:1;
b99028c9
KS
72 unsigned int devlinks_uptodate:1;
73 unsigned int envp_uptodate:1;
74 unsigned int driver_set:1;
75 unsigned int info_loaded:1;
76 unsigned int ignore_remove:1;
11d543c1
KS
77};
78
9a997ecf 79static size_t devpath_to_db_path(struct udev *udev, const char *devpath, char *filename, size_t len)
e88a82b5 80{
065db052
KS
81 char *s;
82 size_t l;
e88a82b5 83
065db052
KS
84 s = filename;
85 l = util_strpcpyl(&s, len, udev_get_dev_path(udev), "/.udev/db/", NULL);
81469dae 86 return util_path_encode(devpath, s, l);
e88a82b5
KS
87}
88
77b852f3 89int udev_device_read_db(struct udev_device *udev_device)
e88a82b5
KS
90{
91 struct stat stats;
3eb46ec6
KS
92 char filename[UTIL_PATH_SIZE];
93 char line[UTIL_LINE_SIZE];
e88a82b5 94 FILE *f;
e88a82b5 95
9a997ecf 96 devpath_to_db_path(udev_device->udev, udev_device->devpath, filename, sizeof(filename));
e88a82b5
KS
97
98 if (lstat(filename, &stats) != 0) {
86b57788 99 dbg(udev_device->udev, "no db file to read %s: %m\n", filename);
e88a82b5
KS
100 return -1;
101 }
102 if ((stats.st_mode & S_IFMT) == S_IFLNK) {
3eb46ec6 103 char target[UTIL_PATH_SIZE];
517814e7 104 char devnode[UTIL_PATH_SIZE];
e88a82b5 105 int target_len;
1e75cda3 106 char *next;
e88a82b5 107
e88a82b5
KS
108 target_len = readlink(filename, target, sizeof(target));
109 if (target_len > 0)
110 target[target_len] = '\0';
111 else {
86b57788 112 dbg(udev_device->udev, "error reading db link %s: %m\n", filename);
e88a82b5
KS
113 return -1;
114 }
1e75cda3
KS
115
116 next = strchr(target, ' ');
117 if (next != NULL) {
118 next[0] = '\0';
119 next = &next[1];
120 }
065db052 121 util_strscpyl(devnode, sizeof(devnode), udev_get_dev_path(udev_device->udev), "/", target, NULL);
517814e7 122 udev_device_set_devnode(udev_device, devnode);
1e75cda3 123 while (next != NULL) {
517814e7 124 char devlink[UTIL_PATH_SIZE];
1e75cda3
KS
125 const char *lnk;
126
127 lnk = next;
128 next = strchr(next, ' ');
129 if (next != NULL) {
130 next[0] = '\0';
131 next = &next[1];
132 }
065db052 133 util_strscpyl(devlink, sizeof(devlink), udev_get_dev_path(udev_device->udev), "/", lnk, NULL);
517814e7 134 udev_device_add_devlink(udev_device, devlink);
1e75cda3 135 }
99214844 136 info(udev_device->udev, "device %p filled with db symlink data '%s'\n", udev_device, udev_device->devnode);
e88a82b5
KS
137 return 0;
138 }
139
140 f = fopen(filename, "r");
141 if (f == NULL) {
86b57788 142 dbg(udev_device->udev, "error reading db file %s: %m\n", filename);
e88a82b5
KS
143 return -1;
144 }
145 while (fgets(line, sizeof(line), f)) {
146 ssize_t len;
147 const char *val;
e88a82b5
KS
148
149 len = strlen(line);
150 if (len < 4)
151 break;
152 line[len-1] = '\0';
153 val = &line[2];
e88a82b5
KS
154 switch(line[0]) {
155 case 'N':
065db052 156 util_strscpyl(filename, sizeof(filename), udev_get_dev_path(udev_device->udev), "/", val, NULL);
517814e7 157 udev_device_set_devnode(udev_device, filename);
e88a82b5 158 break;
e88a82b5 159 case 'S':
065db052 160 util_strscpyl(filename, sizeof(filename), udev_get_dev_path(udev_device->udev), "/", val, NULL);
8cd2e972 161 udev_device_add_devlink(udev_device, filename);
e88a82b5
KS
162 break;
163 case 'L':
8cd2e972 164 udev_device_set_devlink_priority(udev_device, atoi(val));
e88a82b5
KS
165 break;
166 case 'T':
8cd2e972 167 udev_device_set_event_timeout(udev_device, atoi(val));
e88a82b5
KS
168 break;
169 case 'A':
8cd2e972 170 udev_device_set_num_fake_partitions(udev_device, atoi(val));
e88a82b5
KS
171 break;
172 case 'R':
8cd2e972 173 udev_device_set_ignore_remove(udev_device, atoi(val));
e88a82b5
KS
174 break;
175 case 'E':
8cd2e972 176 udev_device_add_property_from_string(udev_device, val);
e88a82b5 177 break;
d7ce7539
SJR
178 case 'W':
179 udev_device_set_watch_handle(udev_device, atoi(val));
180 break;
e88a82b5
KS
181 }
182 }
183 fclose(f);
184
cd42b50d 185 info(udev_device->udev, "device %p filled with db file data\n", udev_device);
04f5d75f 186 return 0;
e88a82b5
KS
187}
188
bd85566c 189int udev_device_read_uevent_file(struct udev_device *udev_device)
99214844
KS
190{
191 char filename[UTIL_PATH_SIZE];
192 FILE *f;
193 char line[UTIL_LINE_SIZE];
194 int maj = 0;
195 int min = 0;
196
065db052 197 util_strscpyl(filename, sizeof(filename), udev_device->syspath, "/uevent", NULL);
99214844
KS
198 f = fopen(filename, "r");
199 if (f == NULL)
200 return -1;
201
202 while (fgets(line, sizeof(line), f)) {
203 char *pos;
204
205 pos = strchr(line, '\n');
206 if (pos == NULL)
207 continue;
208 pos[0] = '\0';
209
bf8b2ae1
MH
210 if (strncmp(line, "DEVTYPE=", 8) == 0)
211 udev_device_set_devtype(udev_device, &line[8]);
212 else if (strncmp(line, "MAJOR=", 6) == 0)
99214844
KS
213 maj = strtoull(&line[6], NULL, 10);
214 else if (strncmp(line, "MINOR=", 6) == 0)
215 min = strtoull(&line[6], NULL, 10);
cb14f454
KS
216 else if (strncmp(line, "DEVNAME=", 8) == 0)
217 udev_device_set_knodename(udev_device, &line[8]);
99214844 218
8cd2e972 219 udev_device_add_property_from_string(udev_device, line);
99214844
KS
220 }
221
222 udev_device->devnum = makedev(maj, min);
223
224 fclose(f);
225 return 0;
226}
227
77b852f3 228static void device_load_info(struct udev_device *device)
99214844 229{
517814e7 230 device->info_loaded = 1;
bd85566c 231 udev_device_read_uevent_file(device);
77b852f3 232 udev_device_read_db(device);
99214844
KS
233}
234
8cd2e972 235void udev_device_set_info_loaded(struct udev_device *device)
99214844
KS
236{
237 device->info_loaded = 1;
238}
239
a5710160 240struct udev_device *udev_device_new(struct udev *udev)
eb1f0e66
KS
241{
242 struct udev_device *udev_device;
ebacd6ec 243 struct udev_list_entry *list_entry;
eb1f0e66 244
ba6929f6
KS
245 if (udev == NULL)
246 return NULL;
247
b29a5e4a 248 udev_device = calloc(1, sizeof(struct udev_device));
eb1f0e66
KS
249 if (udev_device == NULL)
250 return NULL;
eb1f0e66
KS
251 udev_device->refcount = 1;
252 udev_device->udev = udev;
517814e7 253 udev_list_init(&udev_device->devlinks_list);
8cd2e972 254 udev_list_init(&udev_device->properties_list);
69239210 255 udev_list_init(&udev_device->sysattr_list);
979ff016 256 udev_device->event_timeout = -1;
d7ce7539 257 udev_device->watch_handle = -1;
ebacd6ec
KS
258 /* copy global properties */
259 udev_list_entry_foreach(list_entry, udev_get_properties_list_entry(udev))
260 udev_device_add_property(udev_device,
261 udev_list_entry_get_name(list_entry),
262 udev_list_entry_get_value(list_entry));
86b57788 263 dbg(udev_device->udev, "udev_device: %p created\n", udev_device);
eb1f0e66
KS
264 return udev_device;
265}
266
267/**
8753fadf 268 * udev_device_new_from_syspath:
eb1f0e66 269 * @udev: udev library context
8753fadf 270 * @syspath: sys device path including sys directory
eb1f0e66 271 *
8753fadf
KS
272 * Create new udev device, and fill in information from the sys
273 * device and the udev database entry. The sypath is the absolute
274 * path to the device, including the sys mount point.
eb1f0e66
KS
275 *
276 * The initial refcount is 1, and needs to be decremented to
be7de409 277 * release the resources of the udev device.
eb1f0e66
KS
278 *
279 * Returns: a new udev device, or #NULL, if it does not exist
280 **/
8753fadf 281struct udev_device *udev_device_new_from_syspath(struct udev *udev, const char *syspath)
eb1f0e66 282{
b95f8a76
KS
283 size_t len;
284 const char *subdir;
3eb46ec6 285 char path[UTIL_PATH_SIZE];
62b9dfb6 286 char *pos;
eb1f0e66
KS
287 struct stat statbuf;
288 struct udev_device *udev_device;
eb1f0e66 289
ba6929f6
KS
290 if (udev == NULL)
291 return NULL;
8753fadf 292 if (syspath == NULL)
ba6929f6
KS
293 return NULL;
294
b95f8a76
KS
295 /* path starts in sys */
296 len = strlen(udev_get_sys_path(udev));
297 if (strncmp(syspath, udev_get_sys_path(udev), len) != 0) {
298 info(udev, "not in sys :%s\n", syspath);
eb1f0e66 299 return NULL;
4ad3a37f 300 }
eb1f0e66 301
b95f8a76
KS
302 /* path is not a root directory */
303 subdir = &syspath[len+1];
304 pos = strrchr(subdir, '/');
f454f670 305 if (pos == NULL || pos[1] == '\0' || pos < &subdir[2]) {
86b57788 306 dbg(udev, "not a subdir :%s\n", syspath);
eb1f0e66 307 return NULL;
b95f8a76 308 }
eb1f0e66 309
ba6929f6 310 /* resolve possible symlink to real path */
065db052 311 util_strscpy(path, sizeof(path), syspath);
b21b95d7 312 util_resolve_sys_link(udev, path, sizeof(path));
b95f8a76 313
62b9dfb6
KS
314 /* try to resolve the silly block layout if needed */
315 if (strncmp(&path[len], "/block/", 7) == 0) {
316 char block[UTIL_PATH_SIZE];
317 char part[UTIL_PATH_SIZE];
318
065db052 319 util_strscpy(block, sizeof(block), path);
62b9dfb6
KS
320 pos = strrchr(block, '/');
321 if (pos == NULL)
322 return NULL;
065db052 323 util_strscpy(part, sizeof(part), pos);
62b9dfb6 324 pos[0] = '\0';
065db052
KS
325 if (util_resolve_sys_link(udev, block, sizeof(block)) == 0)
326 util_strscpyl(path, sizeof(path), block, part, NULL);
62b9dfb6
KS
327 }
328
b95f8a76
KS
329 /* path exists in sys */
330 if (strncmp(&syspath[len], "/devices/", 9) == 0 ||
331 strncmp(&syspath[len], "/class/", 7) == 0 ||
332 strncmp(&syspath[len], "/block/", 7) == 0) {
333 char file[UTIL_PATH_SIZE];
334
335 /* all "devices" require a "uevent" file */
065db052 336 util_strscpyl(file, sizeof(file), path, "/uevent", NULL);
b95f8a76 337 if (stat(file, &statbuf) != 0) {
86b57788 338 dbg(udev, "not a device: %s\n", syspath);
b95f8a76
KS
339 return NULL;
340 }
341 } else {
342 /* everything else just needs to be a directory */
343 if (stat(path, &statbuf) != 0 || !S_ISDIR(statbuf.st_mode)) {
86b57788 344 dbg(udev, "directory not found: %s\n", syspath);
b95f8a76
KS
345 return NULL;
346 }
347 }
348
a5710160 349 udev_device = udev_device_new(udev);
b95f8a76
KS
350 if (udev_device == NULL)
351 return NULL;
352
8cd2e972 353 udev_device_set_syspath(udev_device, path);
7d563a17 354 info(udev, "device %p has devpath '%s'\n", udev_device, udev_device_get_devpath(udev_device));
eb1f0e66 355
eb1f0e66
KS
356 return udev_device;
357}
358
1e511322
KS
359/**
360 * udev_device_new_from_devnum:
361 * @udev: udev library context
362 * @type: char or block device
363 * @devnum: device major/minor number
364 *
365 * Create new udev device, and fill in information from the sys
366 * device and the udev database entry. The device is looked up
367 * by its major/minor number. Character and block device numbers
368 * are not unique across the two types, they do not share the same
369 * range of numbers.
370 *
371 * The initial refcount is 1, and needs to be decremented to
372 * release the resources of the udev device.
373 *
374 * Returns: a new udev device, or #NULL, if it does not exist
375 **/
4c9dff47
KS
376struct udev_device *udev_device_new_from_devnum(struct udev *udev, char type, dev_t devnum)
377{
378 char path[UTIL_PATH_SIZE];
03198b93 379 const char *type_str;
438d4c3c 380 struct udev_enumerate *udev_enumerate;
0de33a61 381 struct udev_list_entry *list_entry;
bf7ad0ea 382 struct udev_device *device = NULL;
03198b93
KS
383
384 if (type == 'b')
385 type_str = "block";
386 else if (type == 'c')
387 type_str = "char";
388 else
389 return NULL;
4c9dff47 390
b95f8a76 391 /* /sys/dev/{block,char}/<maj>:<min> link */
03198b93
KS
392 snprintf(path, sizeof(path), "%s/dev/%s/%u:%u", udev_get_sys_path(udev),
393 type_str, major(devnum), minor(devnum));
bf7ad0ea
KS
394 if (util_resolve_sys_link(udev, path, sizeof(path)) == 0)
395 return udev_device_new_from_syspath(udev, path);
4c9dff47 396
438d4c3c
KS
397 udev_enumerate = udev_enumerate_new(udev);
398 if (udev_enumerate == NULL)
399 return NULL;
400
bc8184ed
KS
401 /* fallback to search sys devices for the major/minor */
402 if (type == 'b')
c97f839e 403 udev_enumerate_add_match_subsystem(udev_enumerate, "block");
bc8184ed 404 else if (type == 'c')
c97f839e
KS
405 udev_enumerate_add_nomatch_subsystem(udev_enumerate, "block");
406 udev_enumerate_scan_devices(udev_enumerate);
438d4c3c 407 udev_list_entry_foreach(list_entry, udev_enumerate_get_list_entry(udev_enumerate)) {
bf7ad0ea
KS
408 struct udev_device *device_loop;
409
0de33a61 410 device_loop = udev_device_new_from_syspath(udev, udev_list_entry_get_name(list_entry));
bf7ad0ea
KS
411 if (device_loop != NULL) {
412 if (udev_device_get_devnum(device_loop) == devnum) {
c97f839e 413 if (type == 'b' && strcmp(udev_device_get_subsystem(device_loop), "block") != 0)
bc8184ed 414 continue;
c97f839e 415 if (type == 'c' && strcmp(udev_device_get_subsystem(device_loop), "block") == 0)
bc8184ed 416 continue;
bf7ad0ea
KS
417 device = device_loop;
418 break;
419 }
420 udev_device_unref(device_loop);
421 }
bf7ad0ea 422 }
438d4c3c 423 udev_enumerate_unref(udev_enumerate);
bf7ad0ea 424 return device;
4c9dff47
KS
425}
426
1e511322
KS
427/**
428 * udev_device_new_from_subsystem_sysname:
429 * @udev: udev library context
430 * @subsystem: the subsytem of the device
431 * @sysname: the name of the device
432 *
433 * Create new udev device, and fill in information from the sys
434 * device and the udev database entry. The device is looked up
435 * by the subsytem and name string of the device, like "mem",
436 * "zero", or "block", "sda".
437 *
438 * The initial refcount is 1, and needs to be decremented to
439 * release the resources of the udev device.
440 *
441 * Returns: a new udev device, or #NULL, if it does not exist
442 **/
90d80c2e
KS
443struct udev_device *udev_device_new_from_subsystem_sysname(struct udev *udev, const char *subsystem, const char *sysname)
444{
90d80c2e
KS
445 char path_full[UTIL_PATH_SIZE];
446 char *path;
065db052 447 size_t l;
90d80c2e
KS
448 struct stat statbuf;
449
065db052
KS
450 path = path_full;
451 l = util_strpcpyl(&path, sizeof(path_full), udev_get_sys_path(udev), NULL);
90d80c2e
KS
452
453 if (strcmp(subsystem, "subsystem") == 0) {
065db052 454 util_strscpyl(path, l, "/subsystem/", sysname, NULL);
90d80c2e
KS
455 if (stat(path_full, &statbuf) == 0)
456 goto found;
457
065db052 458 util_strscpyl(path, l, "/bus/", sysname, NULL);
90d80c2e
KS
459 if (stat(path_full, &statbuf) == 0)
460 goto found;
461
065db052 462 util_strscpyl(path, l, "/class/", sysname, NULL);
90d80c2e
KS
463 if (stat(path_full, &statbuf) == 0)
464 goto found;
465 goto out;
466 }
467
468 if (strcmp(subsystem, "module") == 0) {
065db052 469 util_strscpyl(path, l, "/module/", sysname, NULL);
90d80c2e
KS
470 if (stat(path_full, &statbuf) == 0)
471 goto found;
472 goto out;
473 }
474
475 if (strcmp(subsystem, "drivers") == 0) {
476 char subsys[UTIL_NAME_SIZE];
477 char *driver;
478
065db052 479 util_strscpy(subsys, sizeof(subsys), sysname);
90d80c2e
KS
480 driver = strchr(subsys, ':');
481 if (driver != NULL) {
482 driver[0] = '\0';
483 driver = &driver[1];
065db052
KS
484
485 util_strscpyl(path, l, "/subsystem/", subsys, "/drivers/", driver, NULL);
90d80c2e
KS
486 if (stat(path_full, &statbuf) == 0)
487 goto found;
488
065db052 489 util_strscpyl(path, l, "/bus/", subsys, "/drivers/", driver, NULL);
90d80c2e
KS
490 if (stat(path_full, &statbuf) == 0)
491 goto found;
492 }
493 goto out;
494 }
495
065db052 496 util_strscpyl(path, l, "/subsystem/", subsystem, "/devices/", sysname, NULL);
90d80c2e
KS
497 if (stat(path_full, &statbuf) == 0)
498 goto found;
499
065db052 500 util_strscpyl(path, l, "/bus/", subsystem, "/devices/", sysname, NULL);
90d80c2e
KS
501 if (stat(path_full, &statbuf) == 0)
502 goto found;
503
065db052 504 util_strscpyl(path, l, "/class/", subsystem, "/", sysname, NULL);
90d80c2e
KS
505 if (stat(path_full, &statbuf) == 0)
506 goto found;
507out:
508 return NULL;
509found:
510 return udev_device_new_from_syspath(udev, path_full);
511}
512
b2d9e4f2 513static struct udev_device *device_new_from_parent(struct udev_device *udev_device)
4ad3a37f
KS
514{
515 struct udev_device *udev_device_parent = NULL;
516 char path[UTIL_PATH_SIZE];
b95f8a76 517 const char *subdir;
4ad3a37f 518
b95f8a76
KS
519 /* follow "device" link in deprecated sys layout */
520 if (strncmp(udev_device->devpath, "/class/", 7) == 0 ||
521 strncmp(udev_device->devpath, "/block/", 7) == 0) {
065db052 522 util_strscpyl(path, sizeof(path), udev_device->syspath, "/device", NULL);
f454ecf7 523 if (util_resolve_sys_link(udev_device->udev, path, sizeof(path)) == 0) {
b95f8a76 524 udev_device_parent = udev_device_new_from_syspath(udev_device->udev, path);
f454ecf7
KS
525 if (udev_device_parent != NULL)
526 return udev_device_parent;
527 }
b95f8a76 528 }
4ad3a37f 529
065db052 530 util_strscpy(path, sizeof(path), udev_device->syspath);
b95f8a76 531 subdir = &path[strlen(udev_get_sys_path(udev_device->udev))+1];
4ad3a37f 532 while (1) {
b95f8a76
KS
533 char *pos;
534
535 pos = strrchr(subdir, '/');
536 if (pos == NULL || pos < &subdir[2])
4ad3a37f
KS
537 break;
538 pos[0] = '\0';
8753fadf 539 udev_device_parent = udev_device_new_from_syspath(udev_device->udev, path);
4ad3a37f 540 if (udev_device_parent != NULL)
0518da3b
KS
541 return udev_device_parent;
542 }
0518da3b 543 return NULL;
4ad3a37f
KS
544}
545
1e511322
KS
546/**
547 * udev_device_get_parent:
548 * @udev_device: the device to start searching from
549 *
550 * Find the next parent device, and fill in information from the sys
551 * device and the udev database entry.
552 *
553 * The returned the device is not referenced. It is attached to the
554 * child device, and will be cleaned up when the child device
555 * is cleaned up.
556 *
557 * It is not neccessarily just the upper level directory, empty or not
558 * recognized sys directories are ignored.
559 *
560 * It can be called as many times as needed, without caring about
561 * references.
562 *
563 * Returns: a new udev device, or #NULL, if it no parent exist.
564 **/
b2d9e4f2
KS
565struct udev_device *udev_device_get_parent(struct udev_device *udev_device)
566{
b95f8a76
KS
567 if (udev_device == NULL)
568 return NULL;
31f4b036
KS
569 if (!udev_device->parent_set) {
570 udev_device->parent_set = 1;
571 udev_device->parent_device = device_new_from_parent(udev_device);
0518da3b 572 }
31f4b036 573 if (udev_device->parent_device != NULL)
86b57788 574 dbg(udev_device->udev, "returning existing parent %p\n", udev_device->parent_device);
b2d9e4f2
KS
575 return udev_device->parent_device;
576}
577
1e511322
KS
578/**
579 * udev_device_get_parent_with_subsystem_devtype:
580 * @udev_device: udev device to start searching from
581 * @subsystem: the subsytem of the device
582 * @devtype: the type (DEVTYPE) of the device
583 *
584 * Find the next parent device, with a matching subsystem and devtype
585 * value, and fill in information from the sys device and the udev
586 * database entry.
587 *
588 * The returned the device is not referenced. It is attached to the
589 * child device, and will be cleaned up when the child device
590 * is cleaned up.
591 *
592 * It can be called as many times as needed, without caring about
593 * references.
594 *
8d6bc73a 595 * Returns: a new udev device, or #NULL if no matching parent exists.
1e511322 596 **/
883012d4 597struct udev_device *udev_device_get_parent_with_subsystem_devtype(struct udev_device *udev_device, const char *subsystem, const char *devtype)
bf8b2ae1
MH
598{
599 struct udev_device *parent;
600
883012d4
MH
601 if (subsystem == NULL)
602 return NULL;
603
bf8b2ae1
MH
604 parent = udev_device_get_parent(udev_device);
605 while (parent != NULL) {
883012d4 606 const char *parent_subsystem;
bf8b2ae1
MH
607 const char *parent_devtype;
608
883012d4
MH
609 parent_subsystem = udev_device_get_subsystem(parent);
610 if (parent_subsystem != NULL && strcmp(parent_subsystem, subsystem) == 0) {
611 if (devtype == NULL)
612 break;
613 parent_devtype = udev_device_get_devtype(parent);
614 if (parent_devtype != NULL && strcmp(parent_devtype, devtype) == 0)
615 break;
616 }
bf8b2ae1
MH
617 parent = udev_device_get_parent(parent);
618 }
619 return parent;
620}
621
eb1f0e66
KS
622/**
623 * udev_device_get_udev:
7d8787b3 624 * @udev_device: udev device
eb1f0e66
KS
625 *
626 * Retrieve the udev library context the device was created with.
627 *
628 * Returns: the udev library context
629 **/
630struct udev *udev_device_get_udev(struct udev_device *udev_device)
631{
ba6929f6
KS
632 if (udev_device == NULL)
633 return NULL;
eb1f0e66
KS
634 return udev_device->udev;
635}
636
637/**
638 * udev_device_ref:
639 * @udev_device: udev device
640 *
641 * Take a reference of a udev device.
642 *
643 * Returns: the passed udev device
644 **/
645struct udev_device *udev_device_ref(struct udev_device *udev_device)
646{
ba6929f6
KS
647 if (udev_device == NULL)
648 return NULL;
eb1f0e66
KS
649 udev_device->refcount++;
650 return udev_device;
651}
652
653/**
654 * udev_device_unref:
655 * @udev_device: udev device
656 *
657 * Drop a reference of a udev device. If the refcount reaches zero,
be7de409 658 * the resources of the device will be released.
eb1f0e66
KS
659 *
660 **/
661void udev_device_unref(struct udev_device *udev_device)
662{
ba6929f6
KS
663 if (udev_device == NULL)
664 return;
eb1f0e66
KS
665 udev_device->refcount--;
666 if (udev_device->refcount > 0)
667 return;
b2d9e4f2
KS
668 if (udev_device->parent_device != NULL)
669 udev_device_unref(udev_device->parent_device);
11d543c1 670 free(udev_device->syspath);
517814e7 671 free(udev_device->sysname);
99214844 672 free(udev_device->devnode);
ba6929f6 673 free(udev_device->subsystem);
bf8b2ae1 674 free(udev_device->devtype);
eb8837e1
KS
675 udev_list_cleanup_entries(udev_device->udev, &udev_device->devlinks_list);
676 udev_list_cleanup_entries(udev_device->udev, &udev_device->properties_list);
1c7047ea
KS
677 free(udev_device->action);
678 free(udev_device->driver);
679 free(udev_device->devpath_old);
cb14f454 680 free(udev_device->knodename);
69239210 681 udev_list_cleanup_entries(udev_device->udev, &udev_device->sysattr_list);
6493e655 682 free(udev_device->envp);
c2654402 683 free(udev_device->monitor_buf);
86b57788 684 dbg(udev_device->udev, "udev_device: %p released\n", udev_device);
eb1f0e66
KS
685 free(udev_device);
686}
687
688/**
689 * udev_device_get_devpath:
690 * @udev_device: udev device
691 *
11d543c1
KS
692 * Retrieve the kernel devpath value of the udev device. The path
693 * does not contain the sys mount point, and starts with a '/'.
eb1f0e66 694 *
11d543c1 695 * Returns: the devpath of the udev device
eb1f0e66
KS
696 **/
697const char *udev_device_get_devpath(struct udev_device *udev_device)
698{
ba6929f6
KS
699 if (udev_device == NULL)
700 return NULL;
701 return udev_device->devpath;
eb1f0e66
KS
702}
703
11d543c1
KS
704/**
705 * udev_device_get_syspath:
706 * @udev_device: udev device
707 *
708 * Retrieve the sys path of the udev device. The path is an
709 * absolute path and starts with the sys mount point.
710 *
711 * Returns: the sys path of the udev device
712 **/
713const char *udev_device_get_syspath(struct udev_device *udev_device)
714{
715 if (udev_device == NULL)
716 return NULL;
717 return udev_device->syspath;
718}
719
1e511322
KS
720/**
721 * udev_device_get_sysname:
722 * @udev_device: udev device
723 *
724 * Returns: the sys name of the device device
725 **/
4ad3a37f
KS
726const char *udev_device_get_sysname(struct udev_device *udev_device)
727{
728 if (udev_device == NULL)
729 return NULL;
730 return udev_device->sysname;
731}
732
1e511322
KS
733/**
734 * udev_device_get_sysnum:
735 * @udev_device: udev device
736 *
737 * Returns: the trailing number of of the device name
738 **/
517814e7
KS
739const char *udev_device_get_sysnum(struct udev_device *udev_device)
740{
741 if (udev_device == NULL)
742 return NULL;
743 return udev_device->sysnum;
744}
745
eb1f0e66 746/**
fb762bb9 747 * udev_device_get_devnode:
eb1f0e66
KS
748 * @udev_device: udev device
749 *
750 * Retrieve the device node file name belonging to the udev device.
ba6929f6 751 * The path is an absolute path, and starts with the device directory.
eb1f0e66
KS
752 *
753 * Returns: the device node file name of the udev device, or #NULL if no device node exists
754 **/
fb762bb9 755const char *udev_device_get_devnode(struct udev_device *udev_device)
eb1f0e66 756{
ba6929f6 757 if (udev_device == NULL)
eb1f0e66 758 return NULL;
99214844 759 if (!udev_device->info_loaded)
77b852f3 760 device_load_info(udev_device);
99214844 761 return udev_device->devnode;
eb1f0e66
KS
762}
763
764/**
765 * udev_device_get_subsystem:
766 * @udev_device: udev device
767 *
768 * Retrieve the subsystem string of the udev device. The string does not
769 * contain any "/".
770 *
771 * Returns: the subsystem name of the udev device, or #NULL if it can not be determined
772 **/
773const char *udev_device_get_subsystem(struct udev_device *udev_device)
774{
17fcfb59 775 char subsystem[UTIL_NAME_SIZE];
ba6929f6
KS
776
777 if (udev_device == NULL)
778 return NULL;
5c5cad79
KS
779 if (!udev_device->subsystem_set) {
780 udev_device->subsystem_set = 1;
781 /* read "subsytem" link */
782 if (util_get_sys_subsystem(udev_device->udev, udev_device->syspath, subsystem, sizeof(subsystem)) > 0) {
783 udev_device_set_subsystem(udev_device, subsystem);
784 return udev_device->subsystem;
785 }
786 /* implicit names */
787 if (strncmp(udev_device->devpath, "/module/", 8) == 0) {
788 udev_device_set_subsystem(udev_device, "module");
789 return udev_device->subsystem;
790 }
791 if (strstr(udev_device->devpath, "/drivers/") != NULL) {
792 udev_device_set_subsystem(udev_device, "drivers");
793 return udev_device->subsystem;
794 }
795 if (strncmp(udev_device->devpath, "/subsystem/", 11) == 0 ||
796 strncmp(udev_device->devpath, "/class/", 7) == 0 ||
797 strncmp(udev_device->devpath, "/bus/", 5) == 0) {
798 udev_device_set_subsystem(udev_device, "subsystem");
799 return udev_device->subsystem;
800 }
0518da3b 801 }
5c5cad79 802 return udev_device->subsystem;
eb1f0e66
KS
803}
804
bf8b2ae1
MH
805/**
806 * udev_device_get_devtype:
807 * @udev_device: udev device
808 *
809 * Retrieve the devtype string of the udev device.
810 *
811 * Returns: the devtype name of the udev device, or #NULL if it can not be determined
812 **/
813const char *udev_device_get_devtype(struct udev_device *udev_device)
814{
815 if (udev_device == NULL)
816 return NULL;
817 if (!udev_device->devtype_set) {
818 udev_device->devtype_set = 1;
b9251174
KS
819 if (!udev_device->info_loaded)
820 udev_device_read_uevent_file(udev_device);
bf8b2ae1
MH
821 }
822 return udev_device->devtype;
823}
824
eb1f0e66 825/**
0de33a61 826 * udev_device_get_devlinks_list_entry:
eb1f0e66 827 * @udev_device: udev device
eb1f0e66 828 *
bf7ad0ea
KS
829 * Retrieve the list of device links pointing to the device file of
830 * the udev device. The next list entry can be retrieved with
e345e267 831 * udev_list_entry_next(), which returns #NULL if no more entries exist.
bf7ad0ea 832 * The devlink path can be retrieved from the list entry by
e345e267 833 * udev_list_entry_get_name(). The path is an absolute path, and starts with
bf7ad0ea 834 * the device directory.
eb1f0e66 835 *
bf7ad0ea 836 * Returns: the first entry of the device node link list
eb1f0e66 837 **/
0de33a61 838struct udev_list_entry *udev_device_get_devlinks_list_entry(struct udev_device *udev_device)
eb1f0e66 839{
99214844
KS
840 if (udev_device == NULL)
841 return NULL;
842 if (!udev_device->info_loaded)
77b852f3 843 device_load_info(udev_device);
517814e7 844 return udev_list_get_entry(&udev_device->devlinks_list);
eb1f0e66
KS
845}
846
979ff016
KS
847void udev_device_cleanup_devlinks_list(struct udev_device *udev_device)
848{
bd85566c 849 udev_device->devlinks_uptodate = 0;
eb8837e1 850 udev_list_cleanup_entries(udev_device->udev, &udev_device->devlinks_list);
979ff016
KS
851}
852
eb1f0e66 853/**
0de33a61 854 * udev_device_get_properties_list_entry:
eb1f0e66 855 * @udev_device: udev device
eb1f0e66 856 *
bf7ad0ea 857 * Retrieve the list of key/value device properties of the udev
e345e267 858 * device. The next list entry can be retrieved with udev_list_entry_next(),
bf7ad0ea
KS
859 * which returns #NULL if no more entries exist. The property name
860 * can be retrieved from the list entry by udev_list_get_name(),
861 * the property value by udev_list_get_value().
eb1f0e66 862 *
bf7ad0ea 863 * Returns: the first entry of the property list
eb1f0e66 864 **/
0de33a61 865struct udev_list_entry *udev_device_get_properties_list_entry(struct udev_device *udev_device)
eb1f0e66 866{
99214844
KS
867 if (udev_device == NULL)
868 return NULL;
869 if (!udev_device->info_loaded)
77b852f3 870 device_load_info(udev_device);
bd85566c
KS
871 if (!udev_device->devlinks_uptodate) {
872 char symlinks[UTIL_PATH_SIZE];
873 struct udev_list_entry *list_entry;
874
875 udev_device->devlinks_uptodate = 1;
876 list_entry = udev_device_get_devlinks_list_entry(udev_device);
877 if (list_entry != NULL) {
065db052
KS
878 char *s;
879 size_t l;
880
881 s = symlinks;
882 l = util_strpcpyl(&s, sizeof(symlinks), udev_list_entry_get_name(list_entry), NULL);
883 udev_list_entry_foreach(list_entry, udev_list_entry_get_next(list_entry))
884 l = util_strpcpyl(&s, l, " ", udev_list_entry_get_name(list_entry), NULL);
bd85566c
KS
885 udev_device_add_property(udev_device, "DEVLINKS", symlinks);
886 }
887 }
8cd2e972 888 return udev_list_get_entry(&udev_device->properties_list);
eb1f0e66 889}
11d543c1 890
1e511322
KS
891/**
892 * udev_device_get_driver:
893 * @udev_device: udev device
894 *
ce1d6d7f 895 * Returns: the driver string, or #NULL if there is no driver attached.
1e511322 896 **/
c4f5f942
KS
897const char *udev_device_get_driver(struct udev_device *udev_device)
898{
17fcfb59 899 char driver[UTIL_NAME_SIZE];
95d90c4f 900
c4f5f942
KS
901 if (udev_device == NULL)
902 return NULL;
5c5cad79
KS
903 if (!udev_device->driver_set) {
904 udev_device->driver_set = 1;
905 if (util_get_sys_driver(udev_device->udev, udev_device->syspath, driver, sizeof(driver)) > 0)
906 udev_device->driver = strdup(driver);
907 }
c4f5f942
KS
908 return udev_device->driver;
909}
910
1e511322
KS
911/**
912 * udev_device_get_devnum:
913 * @udev_device: udev device
914 *
915 * Returns: the device major/minor number.
916 **/
c4f5f942
KS
917dev_t udev_device_get_devnum(struct udev_device *udev_device)
918{
919 if (udev_device == NULL)
920 return makedev(0, 0);
99214844 921 if (!udev_device->info_loaded)
77b852f3 922 device_load_info(udev_device);
c4f5f942
KS
923 return udev_device->devnum;
924}
925
1e511322
KS
926/**
927 * udev_device_get_action:
928 * @udev_device: udev device
929 *
930 * This is only valid if the device was received through a monitor. Devices read from
931 * sys do not have an action string. Usual actions are: add, remove, change, online,
932 * offline.
933 *
934 * Returns: the kernel action value, or #NULL if there is no action value available.
935 **/
c4f5f942
KS
936const char *udev_device_get_action(struct udev_device *udev_device)
937{
938 if (udev_device == NULL)
939 return NULL;
940 return udev_device->action;
941}
942
1e511322
KS
943/**
944 * udev_device_get_devnum:
945 * @udev_device: udev device
946 *
947 * This is only valid if the device was received through a monitor. Devices read from
948 * sys do not have a sequence number.
949 *
950 * Returns: the kernel event sequence number, or 0 if there is no sequence number available.
951 **/
37372bbc
KS
952unsigned long long int udev_device_get_seqnum(struct udev_device *udev_device)
953{
954 if (udev_device == NULL)
955 return 0;
956 return udev_device->seqnum;
957}
958
1e511322
KS
959/**
960 * udev_device_get_sysattr_value:
961 * @udev_device: udev device
962 * @sysattr: attribute name
963 *
964 * The retrieved value is cached in the device. Repeated reads will return the same
965 * value and not open the attribute again.
966 *
967 * Returns: the content of a sys attribute file, or #NULL if there is no sys attribute value.
968 **/
69239210 969const char *udev_device_get_sysattr_value(struct udev_device *udev_device, const char *sysattr)
93b0f384 970{
0de33a61 971 struct udev_list_entry *list_entry;
93b0f384 972 char path[UTIL_PATH_SIZE];
affed87a 973 char value[4096];
93b0f384
KS
974 struct stat statbuf;
975 int fd;
976 ssize_t size;
977 const char *val = NULL;
978
517814e7
KS
979 if (udev_device == NULL)
980 return NULL;
69239210 981 if (sysattr == NULL)
517814e7
KS
982 return NULL;
983
0518da3b 984 /* look for possibly already cached result */
69239210
KS
985 udev_list_entry_foreach(list_entry, udev_list_get_entry(&udev_device->sysattr_list)) {
986 if (strcmp(udev_list_entry_get_name(list_entry), sysattr) == 0) {
86b57788
KS
987 dbg(udev_device->udev, "got '%s' (%s) from cache\n",
988 sysattr, udev_list_entry_get_value(list_entry));
0de33a61 989 return udev_list_entry_get_value(list_entry);
0518da3b
KS
990 }
991 }
992
065db052 993 util_strscpyl(path, sizeof(path), udev_device_get_syspath(udev_device), "/", sysattr, NULL);
93b0f384 994 if (lstat(path, &statbuf) != 0) {
86b57788 995 dbg(udev_device->udev, "no attribute '%s', keep negative entry\n", path);
69239210 996 udev_list_entry_add(udev_device->udev, &udev_device->sysattr_list, sysattr, NULL, 0, 0);
93b0f384
KS
997 goto out;
998 }
999
1000 if (S_ISLNK(statbuf.st_mode)) {
93b0f384
KS
1001 char target[UTIL_NAME_SIZE];
1002 int len;
1003 char *pos;
1004
096e59ed
KS
1005 /* some core links return the last element of the target path */
1006 if (strcmp(sysattr, "driver") != 0 &&
1007 strcmp(sysattr, "subsystem") != 0 &&
1008 strcmp(sysattr, "module") != 0)
1009 goto out;
1010
93b0f384
KS
1011 len = readlink(path, target, sizeof(target));
1012 if (len > 0) {
1013 target[len] = '\0';
1014 pos = strrchr(target, '/');
1015 if (pos != NULL) {
1016 pos = &pos[1];
86b57788 1017 dbg(udev_device->udev, "cache '%s' with link value '%s'\n", sysattr, pos);
69239210 1018 list_entry = udev_list_entry_add(udev_device->udev, &udev_device->sysattr_list, sysattr, pos, 0, 0);
0de33a61 1019 val = udev_list_entry_get_value(list_entry);
93b0f384
KS
1020 }
1021 }
1022 goto out;
1023 }
1024
1025 /* skip directories */
1026 if (S_ISDIR(statbuf.st_mode))
1027 goto out;
1028
1029 /* skip non-readable files */
1030 if ((statbuf.st_mode & S_IRUSR) == 0)
1031 goto out;
1032
1033 /* read attribute value */
1034 fd = open(path, O_RDONLY);
1035 if (fd < 0) {
86b57788 1036 dbg(udev_device->udev, "attribute '%s' can not be opened\n", path);
93b0f384
KS
1037 goto out;
1038 }
1039 size = read(fd, value, sizeof(value));
1040 close(fd);
1041 if (size < 0)
1042 goto out;
1043 if (size == sizeof(value))
1044 goto out;
1045
0518da3b 1046 /* got a valid value, store it in cache and return it */
93b0f384
KS
1047 value[size] = '\0';
1048 util_remove_trailing_chars(value, '\n');
86b57788 1049 dbg(udev_device->udev, "'%s' has attribute value '%s'\n", path, value);
69239210 1050 list_entry = udev_list_entry_add(udev_device->udev, &udev_device->sysattr_list, sysattr, value, 0, 0);
0de33a61 1051 val = udev_list_entry_get_value(list_entry);
93b0f384
KS
1052out:
1053 return val;
1054}
517814e7 1055
8cd2e972 1056int udev_device_set_syspath(struct udev_device *udev_device, const char *syspath)
11d543c1 1057{
8753fadf 1058 const char *pos;
517814e7 1059 size_t len;
8753fadf 1060
8cd2e972 1061 free(udev_device->syspath);
8753fadf
KS
1062 udev_device->syspath = strdup(syspath);
1063 if (udev_device->syspath == NULL)
11d543c1
KS
1064 return -ENOMEM;
1065 udev_device->devpath = &udev_device->syspath[strlen(udev_get_sys_path(udev_device->udev))];
9a997ecf 1066 udev_device_add_property(udev_device, "DEVPATH", udev_device->devpath);
517814e7 1067
8753fadf
KS
1068 pos = strrchr(udev_device->syspath, '/');
1069 if (pos == NULL)
1070 return -EINVAL;
517814e7
KS
1071 udev_device->sysname = strdup(&pos[1]);
1072 if (udev_device->sysname == NULL)
1073 return -ENOMEM;
1074
1075 /* some devices have '!' in their name, change that to '/' */
1076 len = 0;
1077 while (udev_device->sysname[len] != '\0') {
1078 if (udev_device->sysname[len] == '!')
1079 udev_device->sysname[len] = '/';
1080 len++;
1081 }
1082
1083 /* trailing number */
babcf3cb 1084 while (len > 0 && isdigit(udev_device->sysname[--len]))
517814e7 1085 udev_device->sysnum = &udev_device->sysname[len];
babcf3cb
AJ
1086
1087 /* sysname is completely numeric */
1088 if (len == 0)
1089 udev_device->sysnum = NULL;
1090
11d543c1
KS
1091 return 0;
1092}
1093
8cd2e972 1094int udev_device_set_subsystem(struct udev_device *udev_device, const char *subsystem)
11d543c1 1095{
979ff016 1096 free(udev_device->subsystem);
11d543c1
KS
1097 udev_device->subsystem = strdup(subsystem);
1098 if (udev_device->subsystem == NULL)
9a997ecf 1099 return -ENOMEM;
5c5cad79 1100 udev_device->subsystem_set = 1;
9a997ecf 1101 udev_device_add_property(udev_device, "SUBSYSTEM", udev_device->subsystem);
11d543c1
KS
1102 return 0;
1103}
1104
bf8b2ae1
MH
1105int udev_device_set_devtype(struct udev_device *udev_device, const char *devtype)
1106{
1107 free(udev_device->devtype);
1108 udev_device->devtype = strdup(devtype);
1109 if (udev_device->devtype == NULL)
1110 return -ENOMEM;
1111 udev_device->devtype_set = 1;
1112 udev_device_add_property(udev_device, "DEVTYPE", udev_device->devtype);
1113 return 0;
1114}
1115
8cd2e972 1116int udev_device_set_devnode(struct udev_device *udev_device, const char *devnode)
11d543c1 1117{
517814e7 1118 free(udev_device->devnode);
99214844 1119 udev_device->devnode = strdup(devnode);
bd85566c
KS
1120 if (devnode == NULL)
1121 return 0;
99214844 1122 if (udev_device->devnode == NULL)
11d543c1 1123 return -ENOMEM;
979ff016 1124 udev_device_add_property(udev_device, "DEVNAME", udev_device->devnode);
11d543c1
KS
1125 return 0;
1126}
1127
8cd2e972 1128int udev_device_add_devlink(struct udev_device *udev_device, const char *devlink)
11d543c1 1129{
bd85566c 1130 udev_device->devlinks_uptodate = 0;
517814e7 1131 if (udev_list_entry_add(udev_device->udev, &udev_device->devlinks_list, devlink, NULL, 1, 0) == NULL)
11d543c1
KS
1132 return -ENOMEM;
1133 return 0;
1134}
1135
517814e7 1136struct udev_list_entry *udev_device_add_property(struct udev_device *udev_device, const char *key, const char *value)
11d543c1 1137{
979ff016 1138 udev_device->envp_uptodate = 0;
ebacd6ec
KS
1139 if (value == NULL) {
1140 struct udev_list_entry *list_entry;
1141
1142 list_entry = udev_device_get_properties_list_entry(udev_device);
1143 list_entry = udev_list_entry_get_by_name(list_entry, key);
1144 if (list_entry != NULL)
1e78dcbe 1145 udev_list_entry_delete(list_entry);
ebacd6ec
KS
1146 return NULL;
1147 }
517814e7 1148 return udev_list_entry_add(udev_device->udev, &udev_device->properties_list, key, value, 1, 0);
11d543c1 1149}
c4f5f942 1150
517814e7 1151struct udev_list_entry *udev_device_add_property_from_string(struct udev_device *udev_device, const char *property)
0518da3b
KS
1152{
1153 char name[UTIL_PATH_SIZE];
1154 char *val;
1155
065db052 1156 util_strscpy(name, sizeof(name), property);
0518da3b
KS
1157 val = strchr(name, '=');
1158 if (val == NULL)
517814e7 1159 return NULL;
0518da3b
KS
1160 val[0] = '\0';
1161 val = &val[1];
1162 if (val[0] == '\0')
1163 val = NULL;
517814e7 1164 return udev_device_add_property(udev_device, name, val);
0518da3b
KS
1165}
1166
1e511322
KS
1167/**
1168 * udev_device_get_property_value:
1169 * @udev_device: udev device
1170 * @key: property name
1171 *
1172 * Returns: the value of a device property, or #NULL if there is no such property.
1173 **/
3d7b2831
KS
1174const char *udev_device_get_property_value(struct udev_device *udev_device, const char *key)
1175{
1176 struct udev_list_entry *list_entry;
1177
1178 if (udev_device == NULL)
1179 return NULL;
1180 if (key == NULL)
1181 return NULL;
1182
1183 list_entry = udev_device_get_properties_list_entry(udev_device);
1184 list_entry = udev_list_entry_get_by_name(list_entry, key);
1185 return udev_list_entry_get_value(list_entry);
1186}
1187
6493e655
KS
1188#define ENVP_SIZE 128
1189#define MONITOR_BUF_SIZE 4096
1190static int update_envp_monitor_buf(struct udev_device *udev_device)
979ff016 1191{
6493e655 1192 struct udev_list_entry *list_entry;
065db052
KS
1193 char *s;
1194 size_t l;
6493e655 1195 unsigned int i;
979ff016 1196
6493e655
KS
1197 /* monitor buffer of property strings */
1198 free(udev_device->monitor_buf);
1199 udev_device->monitor_buf_len = 0;
1200 udev_device->monitor_buf = malloc(MONITOR_BUF_SIZE);
1201 if (udev_device->monitor_buf == NULL)
1202 return -ENOMEM;
be18918f 1203
6493e655 1204 /* envp array, strings will point into monitor buffer */
427e20b2
KS
1205 if (udev_device->envp == NULL)
1206 udev_device->envp = malloc(sizeof(char *) * ENVP_SIZE);
6493e655
KS
1207 if (udev_device->envp == NULL)
1208 return -ENOMEM;
979ff016 1209
6493e655 1210 i = 0;
065db052
KS
1211 s = udev_device->monitor_buf;
1212 l = MONITOR_BUF_SIZE;
6493e655 1213 udev_list_entry_foreach(list_entry, udev_device_get_properties_list_entry(udev_device)) {
b25a9454
KS
1214 const char *key;
1215
1216 key = udev_list_entry_get_name(list_entry);
1217 /* skip private variables */
1218 if (key[0] == '.')
1219 continue;
1220
6493e655 1221 /* add string to envp array */
065db052 1222 udev_device->envp[i++] = s;
6493e655
KS
1223 if (i+1 >= ENVP_SIZE)
1224 return -EINVAL;
c2654402 1225
6493e655 1226 /* add property string to monitor buffer */
b25a9454 1227 l = util_strpcpyl(&s, l, key, "=", udev_list_entry_get_value(list_entry), NULL);
065db052 1228 if (l == 0)
c2654402 1229 return -EINVAL;
065db052 1230 s++;
c2654402 1231 }
6493e655 1232 udev_device->envp[i] = NULL;
065db052 1233 udev_device->monitor_buf_len = s - udev_device->monitor_buf;
6493e655 1234 udev_device->envp_uptodate = 1;
065db052
KS
1235 dbg(udev_device->udev, "filled envp/monitor buffer, %u properties, %zu bytes\n",
1236 i, udev_device->monitor_buf_len);
6493e655
KS
1237 return 0;
1238}
1239
1240char **udev_device_get_properties_envp(struct udev_device *udev_device)
1241{
1242 if (!udev_device->envp_uptodate)
c6243a41 1243 if (update_envp_monitor_buf(udev_device) != 0)
6493e655
KS
1244 return NULL;
1245 return udev_device->envp;
1246}
1247
1248ssize_t udev_device_get_properties_monitor_buf(struct udev_device *udev_device, const char **buf)
1249{
1250 if (!udev_device->envp_uptodate)
c6243a41 1251 if (update_envp_monitor_buf(udev_device) != 0)
6493e655 1252 return -EINVAL;
c2654402 1253 *buf = udev_device->monitor_buf;
c2654402
KS
1254 return udev_device->monitor_buf_len;
1255}
1256
8cd2e972 1257int udev_device_set_action(struct udev_device *udev_device, const char *action)
c4f5f942 1258{
517814e7 1259 free(udev_device->action);
c4f5f942
KS
1260 udev_device->action = strdup(action);
1261 if (udev_device->action == NULL)
1262 return -ENOMEM;
31f4b036 1263 udev_device_add_property(udev_device, "ACTION", udev_device->action);
c4f5f942
KS
1264 return 0;
1265}
1266
8cd2e972 1267int udev_device_set_driver(struct udev_device *udev_device, const char *driver)
c4f5f942 1268{
979ff016 1269 free(udev_device->driver);
c4f5f942
KS
1270 udev_device->driver = strdup(driver);
1271 if (udev_device->driver == NULL)
1272 return -ENOMEM;
5c5cad79 1273 udev_device->driver_set = 1;
31f4b036 1274 udev_device_add_property(udev_device, "DRIVER", udev_device->driver);
c4f5f942
KS
1275 return 0;
1276}
1277
8cd2e972 1278const char *udev_device_get_devpath_old(struct udev_device *udev_device)
c4f5f942 1279{
c4f5f942
KS
1280 return udev_device->devpath_old;
1281}
1282
8cd2e972 1283int udev_device_set_devpath_old(struct udev_device *udev_device, const char *devpath_old)
c4f5f942
KS
1284{
1285 udev_device->devpath_old = strdup(devpath_old);
1286 if (udev_device->devpath_old == NULL)
1287 return -ENOMEM;
31f4b036 1288 udev_device_add_property(udev_device, "DEVPATH_OLD", udev_device->devpath_old);
c4f5f942
KS
1289 return 0;
1290}
1291
cb14f454
KS
1292const char *udev_device_get_knodename(struct udev_device *udev_device)
1293{
1294 return udev_device->knodename;
1295}
1296
1297int udev_device_set_knodename(struct udev_device *udev_device, const char *knodename)
1298{
1299 udev_device->knodename = strdup(knodename);
1300 if (udev_device->knodename == NULL)
1301 return -ENOMEM;
1302 return 0;
1303}
1304
8cd2e972 1305int udev_device_get_timeout(struct udev_device *udev_device)
c4f5f942 1306{
c4f5f942
KS
1307 return udev_device->timeout;
1308}
1309
8cd2e972 1310int udev_device_set_timeout(struct udev_device *udev_device, int timeout)
c4f5f942
KS
1311{
1312 udev_device->timeout = timeout;
1313 return 0;
1314}
8cd2e972 1315int udev_device_get_event_timeout(struct udev_device *udev_device)
99214844
KS
1316{
1317 if (!udev_device->info_loaded)
77b852f3 1318 device_load_info(udev_device);
99214844
KS
1319 return udev_device->event_timeout;
1320}
1321
8cd2e972 1322int udev_device_set_event_timeout(struct udev_device *udev_device, int event_timeout)
99214844
KS
1323{
1324 udev_device->event_timeout = event_timeout;
1325 return 0;
1326}
c4f5f942 1327
8cd2e972 1328int udev_device_set_seqnum(struct udev_device *udev_device, unsigned long long int seqnum)
37372bbc 1329{
31f4b036
KS
1330 char num[32];
1331
37372bbc 1332 udev_device->seqnum = seqnum;
31f4b036
KS
1333 snprintf(num, sizeof(num), "%llu", seqnum);
1334 udev_device_add_property(udev_device, "SEQNUM", num);
37372bbc
KS
1335 return 0;
1336}
1337
8cd2e972 1338int udev_device_set_devnum(struct udev_device *udev_device, dev_t devnum)
c4f5f942 1339{
31f4b036
KS
1340 char num[32];
1341
c4f5f942 1342 udev_device->devnum = devnum;
31f4b036
KS
1343
1344 snprintf(num, sizeof(num), "%u", major(devnum));
1345 udev_device_add_property(udev_device, "MAJOR", num);
1346 snprintf(num, sizeof(num), "%u", minor(devnum));
1347 udev_device_add_property(udev_device, "MINOR", num);
c4f5f942
KS
1348 return 0;
1349}
6bd1c78a 1350
8cd2e972 1351int udev_device_get_num_fake_partitions(struct udev_device *udev_device)
6bd1c78a 1352{
99214844 1353 if (!udev_device->info_loaded)
77b852f3 1354 device_load_info(udev_device);
6bd1c78a
KS
1355 return udev_device->num_fake_partitions;
1356}
1357
8cd2e972 1358int udev_device_set_num_fake_partitions(struct udev_device *udev_device, int num)
6bd1c78a
KS
1359{
1360 udev_device->num_fake_partitions = num;
e88a82b5 1361 return 0;
6bd1c78a
KS
1362}
1363
8cd2e972 1364int udev_device_get_devlink_priority(struct udev_device *udev_device)
6bd1c78a 1365{
99214844 1366 if (!udev_device->info_loaded)
77b852f3 1367 device_load_info(udev_device);
e88a82b5 1368 return udev_device->devlink_priority;
6bd1c78a
KS
1369}
1370
8cd2e972 1371int udev_device_set_devlink_priority(struct udev_device *udev_device, int prio)
6bd1c78a 1372{
e88a82b5
KS
1373 udev_device->devlink_priority = prio;
1374 return 0;
6bd1c78a
KS
1375}
1376
8cd2e972 1377int udev_device_get_ignore_remove(struct udev_device *udev_device)
6bd1c78a 1378{
99214844 1379 if (!udev_device->info_loaded)
77b852f3 1380 device_load_info(udev_device);
6bd1c78a
KS
1381 return udev_device->ignore_remove;
1382}
1383
8cd2e972 1384int udev_device_set_ignore_remove(struct udev_device *udev_device, int ignore)
6bd1c78a 1385{
e88a82b5
KS
1386 udev_device->ignore_remove = ignore;
1387 return 0;
6bd1c78a 1388}
d7ce7539
SJR
1389
1390int udev_device_get_watch_handle(struct udev_device *udev_device)
1391{
1392 if (!udev_device->info_loaded)
1393 device_load_info(udev_device);
1394 return udev_device->watch_handle;
1395}
1396
1397int udev_device_set_watch_handle(struct udev_device *udev_device, int handle)
1398{
1399 udev_device->watch_handle = handle;
1400 return 0;
1401}