]> git.ipfire.org Git - thirdparty/systemd.git/blame - udev/lib/libudev-device.c
libudev: enumerate - split new() and scan()
[thirdparty/systemd.git] / udev / lib / libudev-device.c
CommitLineData
eb1f0e66
KS
1/*
2 * libudev - interface to udev device information
3 *
4 * Copyright (C) 2008 Kay Sievers <kay.sievers@vrfy.org>
5 *
6 * This program is free software: you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation, either version 2 of the License, or
9 * (at your option) any later version.
10 *
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
15 *
16 * You should have received a copy of the GNU General Public License
17 * along with this program. If not, see <http://www.gnu.org/licenses/>.
18 */
19
eb1f0e66
KS
20#include <stdio.h>
21#include <stdlib.h>
22#include <stddef.h>
23#include <unistd.h>
24#include <errno.h>
25#include <string.h>
26#include <dirent.h>
93b0f384 27#include <fcntl.h>
eb1f0e66
KS
28#include <sys/stat.h>
29
30#include "libudev.h"
31#include "libudev-private.h"
eb1f0e66 32
11d543c1
KS
33struct udev_device {
34 int refcount;
35 struct udev *udev;
b2d9e4f2 36 struct udev_device *parent_device;
11d543c1 37 char *syspath;
4ad3a37f
KS
38 const char *devpath;
39 const char *sysname;
99214844 40 char *devnode;
11d543c1 41 char *subsystem;
e345e267
KS
42 struct list_node devlink_list;
43 struct list_node properties_list;
c4f5f942 44 char *action;
99214844 45 int event_timeout;
c4f5f942
KS
46 char *driver;
47 char *devpath_old;
48 char *physdevpath;
49 int timeout;
50 dev_t devnum;
6bd1c78a
KS
51 unsigned long long int seqnum;
52 int num_fake_partitions;
e88a82b5 53 int devlink_priority;
6bd1c78a 54 int ignore_remove;
e345e267 55 struct list_node attr_list;
99214844 56 int info_loaded;
11d543c1
KS
57};
58
8753fadf 59static size_t syspath_to_db_path(struct udev_device *udev_device, char *filename, size_t len)
e88a82b5
KS
60{
61 size_t start;
62
63 /* translate to location of db file */
8753fadf 64 util_strlcpy(filename, udev_get_dev_path(udev_device->udev), len);
3eb46ec6 65 start = util_strlcat(filename, "/.udev/db/", len);
8753fadf 66 util_strlcat(filename, udev_device->devpath, len);
7a01f11a 67 return util_path_encode(&filename[start], len - start);
e88a82b5
KS
68}
69
70static int device_read_db(struct udev_device *udev_device)
71{
72 struct stat stats;
3eb46ec6
KS
73 char filename[UTIL_PATH_SIZE];
74 char line[UTIL_LINE_SIZE];
e88a82b5 75 FILE *f;
e88a82b5 76
8753fadf 77 syspath_to_db_path(udev_device, filename, sizeof(filename));
e88a82b5
KS
78
79 if (lstat(filename, &stats) != 0) {
80 info(udev_device->udev, "no db file to read %s: %s\n", filename, strerror(errno));
81 return -1;
82 }
83 if ((stats.st_mode & S_IFMT) == S_IFLNK) {
3eb46ec6 84 char target[UTIL_PATH_SIZE];
e88a82b5
KS
85 int target_len;
86
e88a82b5
KS
87 target_len = readlink(filename, target, sizeof(target));
88 if (target_len > 0)
89 target[target_len] = '\0';
90 else {
91 info(udev_device->udev, "error reading db link %s: %s\n", filename, strerror(errno));
92 return -1;
93 }
99214844 94 if (asprintf(&udev_device->devnode, "%s/%s", udev_get_dev_path(udev_device->udev), target) < 0)
e88a82b5 95 return -ENOMEM;
99214844 96 info(udev_device->udev, "device %p filled with db symlink data '%s'\n", udev_device, udev_device->devnode);
e88a82b5
KS
97 return 0;
98 }
99
100 f = fopen(filename, "r");
101 if (f == NULL) {
102 info(udev_device->udev, "error reading db file %s: %s\n", filename, strerror(errno));
103 return -1;
104 }
105 while (fgets(line, sizeof(line), f)) {
106 ssize_t len;
107 const char *val;
e88a82b5
KS
108
109 len = strlen(line);
110 if (len < 4)
111 break;
112 line[len-1] = '\0';
113 val = &line[2];
114
115 switch(line[0]) {
116 case 'N':
99214844 117 asprintf(&udev_device->devnode, "%s/%s", udev_get_dev_path(udev_device->udev), val);
e88a82b5 118 break;
e88a82b5 119 case 'S':
3eb46ec6
KS
120 util_strlcpy(filename, udev_get_dev_path(udev_device->udev), sizeof(filename));
121 util_strlcat(filename, "/", sizeof(filename));
122 util_strlcat(filename, val, sizeof(filename));
e88a82b5
KS
123 device_add_devlink(udev_device, filename);
124 break;
125 case 'L':
126 device_set_devlink_priority(udev_device, atoi(val));
127 break;
128 case 'T':
99214844 129 device_set_event_timeout(udev_device, atoi(val));
e88a82b5
KS
130 break;
131 case 'A':
132 device_set_num_fake_partitions(udev_device, atoi(val));
133 break;
134 case 'R':
135 device_set_ignore_remove(udev_device, atoi(val));
136 break;
137 case 'E':
0518da3b 138 device_add_property_from_string(udev_device, val);
e88a82b5
KS
139 break;
140 }
141 }
142 fclose(f);
143
cd42b50d 144 info(udev_device->udev, "device %p filled with db file data\n", udev_device);
04f5d75f 145 return 0;
e88a82b5
KS
146}
147
99214844
KS
148static int device_read_uevent_file(struct udev_device *udev_device)
149{
150 char filename[UTIL_PATH_SIZE];
151 FILE *f;
152 char line[UTIL_LINE_SIZE];
153 int maj = 0;
154 int min = 0;
155
156 util_strlcpy(filename, udev_device->syspath, sizeof(filename));
157 util_strlcat(filename, "/uevent", sizeof(filename));
158 f = fopen(filename, "r");
159 if (f == NULL)
160 return -1;
161
162 while (fgets(line, sizeof(line), f)) {
163 char *pos;
164
165 pos = strchr(line, '\n');
166 if (pos == NULL)
167 continue;
168 pos[0] = '\0';
169
170 if (strncmp(line, "MAJOR=", 6) == 0)
171 maj = strtoull(&line[6], NULL, 10);
172 else if (strncmp(line, "MINOR=", 6) == 0)
173 min = strtoull(&line[6], NULL, 10);
174
175 device_add_property_from_string(udev_device, line);
176 }
177
178 udev_device->devnum = makedev(maj, min);
179
180 fclose(f);
181 return 0;
182}
183
184static void device_load_info(struct udev_device *device)
185{
186 device_read_uevent_file(device);
187 device_read_db(device);
188 device->info_loaded = 1;
189}
190
191void device_set_info_loaded(struct udev_device *device)
192{
193 device->info_loaded = 1;
194}
195
ba6929f6 196struct udev_device *device_init(struct udev *udev)
eb1f0e66
KS
197{
198 struct udev_device *udev_device;
199
ba6929f6
KS
200 if (udev == NULL)
201 return NULL;
202
eb1f0e66
KS
203 udev_device = malloc(sizeof(struct udev_device));
204 if (udev_device == NULL)
205 return NULL;
206 memset(udev_device, 0x00, sizeof(struct udev_device));
207 udev_device->refcount = 1;
208 udev_device->udev = udev;
e345e267
KS
209 list_init(&udev_device->devlink_list);
210 list_init(&udev_device->properties_list);
211 list_init(&udev_device->attr_list);
7d563a17 212 info(udev_device->udev, "udev_device: %p created\n", udev_device);
eb1f0e66
KS
213 return udev_device;
214}
215
216/**
8753fadf 217 * udev_device_new_from_syspath:
eb1f0e66 218 * @udev: udev library context
8753fadf 219 * @syspath: sys device path including sys directory
eb1f0e66 220 *
8753fadf
KS
221 * Create new udev device, and fill in information from the sys
222 * device and the udev database entry. The sypath is the absolute
223 * path to the device, including the sys mount point.
eb1f0e66
KS
224 *
225 * The initial refcount is 1, and needs to be decremented to
226 * release the ressources of the udev device.
227 *
228 * Returns: a new udev device, or #NULL, if it does not exist
229 **/
8753fadf 230struct udev_device *udev_device_new_from_syspath(struct udev *udev, const char *syspath)
eb1f0e66 231{
b95f8a76
KS
232 size_t len;
233 const char *subdir;
234 const char *pos;
3eb46ec6 235 char path[UTIL_PATH_SIZE];
eb1f0e66
KS
236 struct stat statbuf;
237 struct udev_device *udev_device;
eb1f0e66 238
ba6929f6
KS
239 if (udev == NULL)
240 return NULL;
8753fadf 241 if (syspath == NULL)
ba6929f6
KS
242 return NULL;
243
b95f8a76
KS
244 /* path starts in sys */
245 len = strlen(udev_get_sys_path(udev));
246 if (strncmp(syspath, udev_get_sys_path(udev), len) != 0) {
247 info(udev, "not in sys :%s\n", syspath);
eb1f0e66 248 return NULL;
4ad3a37f 249 }
eb1f0e66 250
b95f8a76
KS
251 /* path is not a root directory */
252 subdir = &syspath[len+1];
253 pos = strrchr(subdir, '/');
254 if (pos == NULL || pos < &subdir[2]) {
bc8184ed 255 info(udev, "not a subdir :%s\n", syspath);
eb1f0e66 256 return NULL;
b95f8a76 257 }
eb1f0e66 258
ba6929f6 259 /* resolve possible symlink to real path */
8753fadf 260 util_strlcpy(path, syspath, sizeof(path));
b21b95d7 261 util_resolve_sys_link(udev, path, sizeof(path));
b95f8a76
KS
262
263 /* path exists in sys */
264 if (strncmp(&syspath[len], "/devices/", 9) == 0 ||
265 strncmp(&syspath[len], "/class/", 7) == 0 ||
266 strncmp(&syspath[len], "/block/", 7) == 0) {
267 char file[UTIL_PATH_SIZE];
268
269 /* all "devices" require a "uevent" file */
270 util_strlcpy(file, path, sizeof(file));
271 util_strlcat(file, "/uevent", sizeof(file));
272 if (stat(file, &statbuf) != 0) {
273 info(udev, "not a device: %s\n", syspath);
274 return NULL;
275 }
276 } else {
277 /* everything else just needs to be a directory */
278 if (stat(path, &statbuf) != 0 || !S_ISDIR(statbuf.st_mode)) {
279 info(udev, "directory not found: %s\n", syspath);
280 return NULL;
281 }
282 }
283
284 udev_device = device_init(udev);
285 if (udev_device == NULL)
286 return NULL;
287
8753fadf 288 device_set_syspath(udev_device, path);
7d563a17 289 info(udev, "device %p has devpath '%s'\n", udev_device, udev_device_get_devpath(udev_device));
eb1f0e66 290
eb1f0e66
KS
291 return udev_device;
292}
293
4c9dff47
KS
294struct udev_device *udev_device_new_from_devnum(struct udev *udev, char type, dev_t devnum)
295{
296 char path[UTIL_PATH_SIZE];
03198b93 297 const char *type_str;
438d4c3c 298 struct udev_enumerate *udev_enumerate;
0de33a61 299 struct udev_list_entry *list_entry;
bf7ad0ea 300 struct udev_device *device = NULL;
03198b93
KS
301
302 if (type == 'b')
303 type_str = "block";
304 else if (type == 'c')
305 type_str = "char";
306 else
307 return NULL;
4c9dff47 308
b95f8a76 309 /* /sys/dev/{block,char}/<maj>:<min> link */
03198b93
KS
310 snprintf(path, sizeof(path), "%s/dev/%s/%u:%u", udev_get_sys_path(udev),
311 type_str, major(devnum), minor(devnum));
bf7ad0ea
KS
312 if (util_resolve_sys_link(udev, path, sizeof(path)) == 0)
313 return udev_device_new_from_syspath(udev, path);
4c9dff47 314
438d4c3c
KS
315 udev_enumerate = udev_enumerate_new(udev);
316 if (udev_enumerate == NULL)
317 return NULL;
318
bc8184ed
KS
319 /* fallback to search sys devices for the major/minor */
320 if (type == 'b')
438d4c3c 321 udev_enumerate_scan_devices(udev_enumerate, "block", NULL);
bc8184ed 322 else if (type == 'c')
438d4c3c
KS
323 udev_enumerate_scan_devices(udev_enumerate, "!block", NULL);
324 udev_list_entry_foreach(list_entry, udev_enumerate_get_list_entry(udev_enumerate)) {
bf7ad0ea
KS
325 struct udev_device *device_loop;
326
0de33a61 327 device_loop = udev_device_new_from_syspath(udev, udev_list_entry_get_name(list_entry));
bf7ad0ea
KS
328 if (device_loop != NULL) {
329 if (udev_device_get_devnum(device_loop) == devnum) {
bc8184ed
KS
330 const char *subsystem;
331
332 subsystem = udev_device_get_subsystem(device_loop);
333 if (type == 'b' && strcmp(subsystem, "block") != 0)
334 continue;
335 if (type == 'c' && strcmp(subsystem, "block") == 0)
336 continue;
bf7ad0ea
KS
337 device = device_loop;
338 break;
339 }
340 udev_device_unref(device_loop);
341 }
bf7ad0ea 342 }
438d4c3c 343 udev_enumerate_unref(udev_enumerate);
bf7ad0ea 344 return device;
4c9dff47
KS
345}
346
b2d9e4f2 347static struct udev_device *device_new_from_parent(struct udev_device *udev_device)
4ad3a37f
KS
348{
349 struct udev_device *udev_device_parent = NULL;
350 char path[UTIL_PATH_SIZE];
b95f8a76 351 const char *subdir;
4ad3a37f 352
b95f8a76
KS
353 /* follow "device" link in deprecated sys layout */
354 if (strncmp(udev_device->devpath, "/class/", 7) == 0 ||
355 strncmp(udev_device->devpath, "/block/", 7) == 0) {
356 util_strlcpy(path, udev_device->syspath, sizeof(path));
357 util_strlcat(path, "/device", sizeof(path));
358 if (util_resolve_sys_link(udev_device->udev, path, sizeof(path)) == 0)
359 udev_device_parent = udev_device_new_from_syspath(udev_device->udev, path);
360 return udev_device_parent;
361 }
4ad3a37f 362
8753fadf 363 util_strlcpy(path, udev_device->syspath, sizeof(path));
b95f8a76 364 subdir = &path[strlen(udev_get_sys_path(udev_device->udev))+1];
4ad3a37f 365 while (1) {
b95f8a76
KS
366 char *pos;
367
368 pos = strrchr(subdir, '/');
369 if (pos == NULL || pos < &subdir[2])
4ad3a37f
KS
370 break;
371 pos[0] = '\0';
8753fadf 372 udev_device_parent = udev_device_new_from_syspath(udev_device->udev, path);
4ad3a37f 373 if (udev_device_parent != NULL)
0518da3b
KS
374 return udev_device_parent;
375 }
0518da3b 376 return NULL;
4ad3a37f
KS
377}
378
b2d9e4f2
KS
379struct udev_device *udev_device_get_parent(struct udev_device *udev_device)
380{
b95f8a76
KS
381 if (udev_device == NULL)
382 return NULL;
383
0518da3b
KS
384 if (udev_device->parent_device != NULL) {
385 info(udev_device->udev, "returning existing parent %p\n", udev_device->parent_device);
386 return udev_device->parent_device;
387 }
388 udev_device->parent_device = device_new_from_parent(udev_device);
b2d9e4f2
KS
389 return udev_device->parent_device;
390}
391
eb1f0e66
KS
392/**
393 * udev_device_get_udev:
7d8787b3 394 * @udev_device: udev device
eb1f0e66
KS
395 *
396 * Retrieve the udev library context the device was created with.
397 *
398 * Returns: the udev library context
399 **/
400struct udev *udev_device_get_udev(struct udev_device *udev_device)
401{
ba6929f6
KS
402 if (udev_device == NULL)
403 return NULL;
eb1f0e66
KS
404 return udev_device->udev;
405}
406
407/**
408 * udev_device_ref:
409 * @udev_device: udev device
410 *
411 * Take a reference of a udev device.
412 *
413 * Returns: the passed udev device
414 **/
415struct udev_device *udev_device_ref(struct udev_device *udev_device)
416{
ba6929f6
KS
417 if (udev_device == NULL)
418 return NULL;
eb1f0e66
KS
419 udev_device->refcount++;
420 return udev_device;
421}
422
423/**
424 * udev_device_unref:
425 * @udev_device: udev device
426 *
427 * Drop a reference of a udev device. If the refcount reaches zero,
428 * the ressources of the device will be released.
429 *
430 **/
431void udev_device_unref(struct udev_device *udev_device)
432{
ba6929f6
KS
433 if (udev_device == NULL)
434 return;
eb1f0e66
KS
435 udev_device->refcount--;
436 if (udev_device->refcount > 0)
437 return;
b2d9e4f2
KS
438 if (udev_device->parent_device != NULL)
439 udev_device_unref(udev_device->parent_device);
11d543c1 440 free(udev_device->syspath);
99214844 441 free(udev_device->devnode);
ba6929f6 442 free(udev_device->subsystem);
99214844 443 list_cleanup(udev_device->udev, &udev_device->devlink_list);
bf7ad0ea 444 list_cleanup(udev_device->udev, &udev_device->properties_list);
1c7047ea
KS
445 free(udev_device->action);
446 free(udev_device->driver);
447 free(udev_device->devpath_old);
448 free(udev_device->physdevpath);
bf7ad0ea 449 list_cleanup(udev_device->udev, &udev_device->attr_list);
7d563a17 450 info(udev_device->udev, "udev_device: %p released\n", udev_device);
eb1f0e66
KS
451 free(udev_device);
452}
453
454/**
455 * udev_device_get_devpath:
456 * @udev_device: udev device
457 *
11d543c1
KS
458 * Retrieve the kernel devpath value of the udev device. The path
459 * does not contain the sys mount point, and starts with a '/'.
eb1f0e66 460 *
11d543c1 461 * Returns: the devpath of the udev device
eb1f0e66
KS
462 **/
463const char *udev_device_get_devpath(struct udev_device *udev_device)
464{
ba6929f6
KS
465 if (udev_device == NULL)
466 return NULL;
467 return udev_device->devpath;
eb1f0e66
KS
468}
469
11d543c1
KS
470/**
471 * udev_device_get_syspath:
472 * @udev_device: udev device
473 *
474 * Retrieve the sys path of the udev device. The path is an
475 * absolute path and starts with the sys mount point.
476 *
477 * Returns: the sys path of the udev device
478 **/
479const char *udev_device_get_syspath(struct udev_device *udev_device)
480{
481 if (udev_device == NULL)
482 return NULL;
483 return udev_device->syspath;
484}
485
4ad3a37f
KS
486const char *udev_device_get_sysname(struct udev_device *udev_device)
487{
488 if (udev_device == NULL)
489 return NULL;
490 return udev_device->sysname;
491}
492
eb1f0e66 493/**
fb762bb9 494 * udev_device_get_devnode:
eb1f0e66
KS
495 * @udev_device: udev device
496 *
497 * Retrieve the device node file name belonging to the udev device.
ba6929f6 498 * The path is an absolute path, and starts with the device directory.
eb1f0e66
KS
499 *
500 * Returns: the device node file name of the udev device, or #NULL if no device node exists
501 **/
fb762bb9 502const char *udev_device_get_devnode(struct udev_device *udev_device)
eb1f0e66 503{
ba6929f6 504 if (udev_device == NULL)
eb1f0e66 505 return NULL;
99214844
KS
506 if (!udev_device->info_loaded)
507 device_load_info(udev_device);
508 return udev_device->devnode;
eb1f0e66
KS
509}
510
511/**
512 * udev_device_get_subsystem:
513 * @udev_device: udev device
514 *
515 * Retrieve the subsystem string of the udev device. The string does not
516 * contain any "/".
517 *
518 * Returns: the subsystem name of the udev device, or #NULL if it can not be determined
519 **/
520const char *udev_device_get_subsystem(struct udev_device *udev_device)
521{
17fcfb59 522 char subsystem[UTIL_NAME_SIZE];
ba6929f6
KS
523
524 if (udev_device == NULL)
525 return NULL;
526 if (udev_device->subsystem != NULL)
527 return udev_device->subsystem;
0518da3b
KS
528
529 /* read "subsytem" link */
279595bd 530 if (util_get_sys_subsystem(udev_device->udev, udev_device->syspath, subsystem, sizeof(subsystem)) > 0) {
0518da3b
KS
531 udev_device->subsystem = strdup(subsystem);
532 return udev_device->subsystem;
533 }
534
535 /* implicit names */
536 if (strncmp(udev_device->devpath, "/module/", 8) == 0) {
537 udev_device->subsystem = strdup("module");
538 return udev_device->subsystem;
539 }
540 if (strstr(udev_device->devpath, "/drivers/") != NULL) {
541 udev_device->subsystem = strdup("drivers");
542 return udev_device->subsystem;
543 }
544 if (strncmp(udev_device->devpath, "/subsystem/", 11) == 0 ||
545 strncmp(udev_device->devpath, "/class/", 7) == 0 ||
546 strncmp(udev_device->devpath, "/bus/", 5) == 0) {
547 udev_device->subsystem = strdup("subsystem");
548 return udev_device->subsystem;
549 }
550 return NULL;
eb1f0e66
KS
551}
552
553/**
0de33a61 554 * udev_device_get_devlinks_list_entry:
eb1f0e66 555 * @udev_device: udev device
eb1f0e66 556 *
bf7ad0ea
KS
557 * Retrieve the list of device links pointing to the device file of
558 * the udev device. The next list entry can be retrieved with
e345e267 559 * udev_list_entry_next(), which returns #NULL if no more entries exist.
bf7ad0ea 560 * The devlink path can be retrieved from the list entry by
e345e267 561 * udev_list_entry_get_name(). The path is an absolute path, and starts with
bf7ad0ea 562 * the device directory.
eb1f0e66 563 *
bf7ad0ea 564 * Returns: the first entry of the device node link list
eb1f0e66 565 **/
0de33a61 566struct udev_list_entry *udev_device_get_devlinks_list_entry(struct udev_device *udev_device)
eb1f0e66 567{
99214844
KS
568 if (udev_device == NULL)
569 return NULL;
570 if (!udev_device->info_loaded)
571 device_load_info(udev_device);
572 return list_get_entry(&udev_device->devlink_list);
eb1f0e66
KS
573}
574
575/**
0de33a61 576 * udev_device_get_properties_list_entry:
eb1f0e66 577 * @udev_device: udev device
eb1f0e66 578 *
bf7ad0ea 579 * Retrieve the list of key/value device properties of the udev
e345e267 580 * device. The next list entry can be retrieved with udev_list_entry_next(),
bf7ad0ea
KS
581 * which returns #NULL if no more entries exist. The property name
582 * can be retrieved from the list entry by udev_list_get_name(),
583 * the property value by udev_list_get_value().
eb1f0e66 584 *
bf7ad0ea 585 * Returns: the first entry of the property list
eb1f0e66 586 **/
0de33a61 587struct udev_list_entry *udev_device_get_properties_list_entry(struct udev_device *udev_device)
eb1f0e66 588{
99214844
KS
589 if (udev_device == NULL)
590 return NULL;
591 if (!udev_device->info_loaded)
592 device_load_info(udev_device);
bf7ad0ea 593 return list_get_entry(&udev_device->properties_list);
eb1f0e66 594}
11d543c1 595
c4f5f942
KS
596const char *udev_device_get_driver(struct udev_device *udev_device)
597{
17fcfb59 598 char driver[UTIL_NAME_SIZE];
95d90c4f 599
c4f5f942
KS
600 if (udev_device == NULL)
601 return NULL;
95d90c4f
KS
602 if (udev_device->driver != NULL)
603 return udev_device->driver;
8753fadf 604 if (util_get_sys_driver(udev_device->udev, udev_device->syspath, driver, sizeof(driver)) < 2)
95d90c4f
KS
605 return NULL;
606 udev_device->driver = strdup(driver);
c4f5f942
KS
607 return udev_device->driver;
608}
609
610dev_t udev_device_get_devnum(struct udev_device *udev_device)
611{
612 if (udev_device == NULL)
613 return makedev(0, 0);
99214844
KS
614 if (!udev_device->info_loaded)
615 device_load_info(udev_device);
c4f5f942
KS
616 return udev_device->devnum;
617}
618
619const char *udev_device_get_action(struct udev_device *udev_device)
620{
621 if (udev_device == NULL)
622 return NULL;
623 return udev_device->action;
624}
625
37372bbc
KS
626unsigned long long int udev_device_get_seqnum(struct udev_device *udev_device)
627{
628 if (udev_device == NULL)
629 return 0;
630 return udev_device->seqnum;
631}
632
93b0f384
KS
633const char *udev_device_get_attr_value(struct udev_device *udev_device, const char *attr)
634{
0de33a61 635 struct udev_list_entry *list_entry;
93b0f384
KS
636 char path[UTIL_PATH_SIZE];
637 char value[UTIL_NAME_SIZE];
638 struct stat statbuf;
639 int fd;
640 ssize_t size;
641 const char *val = NULL;
642
0518da3b 643 /* look for possibly already cached result */
0de33a61
KS
644 udev_list_entry_foreach(list_entry, list_get_entry(&udev_device->attr_list)) {
645 if (strcmp(udev_list_entry_get_name(list_entry), attr) == 0) {
646 info(udev_device->udev, "got '%s' (%s) from cache\n", attr, udev_list_entry_get_value(list_entry));
647 return udev_list_entry_get_value(list_entry);
0518da3b
KS
648 }
649 }
650
93b0f384
KS
651 util_strlcpy(path, udev_device_get_syspath(udev_device), sizeof(path));
652 util_strlcat(path, "/", sizeof(path));
653 util_strlcat(path, attr, sizeof(path));
654
655 if (lstat(path, &statbuf) != 0) {
656 info(udev_device->udev, "stat '%s' failed: %s\n", path, strerror(errno));
657 goto out;
658 }
659
660 if (S_ISLNK(statbuf.st_mode)) {
661 /* links return the last element of the target path */
662 char target[UTIL_NAME_SIZE];
663 int len;
664 char *pos;
665
666 len = readlink(path, target, sizeof(target));
667 if (len > 0) {
668 target[len] = '\0';
669 pos = strrchr(target, '/');
670 if (pos != NULL) {
671 pos = &pos[1];
672 info(udev_device->udev, "cache '%s' with link value '%s'\n", attr, pos);
0de33a61
KS
673 list_entry = list_entry_add(udev_device->udev, &udev_device->attr_list, attr, pos, 0, 0);
674 val = udev_list_entry_get_value(list_entry);
93b0f384
KS
675 }
676 }
677 goto out;
678 }
679
680 /* skip directories */
681 if (S_ISDIR(statbuf.st_mode))
682 goto out;
683
684 /* skip non-readable files */
685 if ((statbuf.st_mode & S_IRUSR) == 0)
686 goto out;
687
688 /* read attribute value */
689 fd = open(path, O_RDONLY);
690 if (fd < 0) {
691 info(udev_device->udev, "attribute '%s' can not be opened\n", path);
692 goto out;
693 }
694 size = read(fd, value, sizeof(value));
695 close(fd);
696 if (size < 0)
697 goto out;
698 if (size == sizeof(value))
699 goto out;
700
0518da3b 701 /* got a valid value, store it in cache and return it */
93b0f384
KS
702 value[size] = '\0';
703 util_remove_trailing_chars(value, '\n');
704 info(udev_device->udev, "'%s' has attribute value '%s'\n", path, value);
0de33a61
KS
705 list_entry = list_entry_add(udev_device->udev, &udev_device->attr_list, attr, value, 0, 0);
706 val = udev_list_entry_get_value(list_entry);
93b0f384
KS
707out:
708 return val;
709}
8753fadf 710int device_set_syspath(struct udev_device *udev_device, const char *syspath)
11d543c1 711{
8753fadf
KS
712 const char *pos;
713
714 udev_device->syspath = strdup(syspath);
715 if (udev_device->syspath == NULL)
11d543c1
KS
716 return -ENOMEM;
717 udev_device->devpath = &udev_device->syspath[strlen(udev_get_sys_path(udev_device->udev))];
8753fadf
KS
718 pos = strrchr(udev_device->syspath, '/');
719 if (pos == NULL)
720 return -EINVAL;
721 udev_device->sysname = &pos[1];
11d543c1
KS
722 return 0;
723}
724
725int device_set_subsystem(struct udev_device *udev_device, const char *subsystem)
726{
727 udev_device->subsystem = strdup(subsystem);
728 if (udev_device->subsystem == NULL)
729 return -1;
730 return 0;
731}
732
99214844 733int device_set_devnode(struct udev_device *udev_device, const char *devnode)
11d543c1 734{
99214844
KS
735 udev_device->devnode = strdup(devnode);
736 if (udev_device->devnode == NULL)
11d543c1
KS
737 return -ENOMEM;
738 return 0;
739}
740
741int device_add_devlink(struct udev_device *udev_device, const char *devlink)
742{
0de33a61 743 if (list_entry_add(udev_device->udev, &udev_device->devlink_list, devlink, NULL, 1, 0) == NULL)
11d543c1
KS
744 return -ENOMEM;
745 return 0;
746}
747
0518da3b 748int device_add_property(struct udev_device *udev_device, const char *key, const char *value)
11d543c1 749{
0de33a61 750 if (list_entry_add(udev_device->udev, &udev_device->properties_list, key, value, 1, 0) == NULL)
11d543c1
KS
751 return -ENOMEM;
752 return 0;
753}
c4f5f942 754
0518da3b
KS
755int device_add_property_from_string(struct udev_device *udev_device, const char *property)
756{
757 char name[UTIL_PATH_SIZE];
758 char *val;
759
760 strncpy(name, property, sizeof(name));
761 val = strchr(name, '=');
762 if (val == NULL)
763 return -1;
764 val[0] = '\0';
765 val = &val[1];
766 if (val[0] == '\0')
767 val = NULL;
768 device_add_property(udev_device, name, val);
769 return 0;
770}
771
c4f5f942
KS
772int device_set_action(struct udev_device *udev_device, const char *action)
773{
774 udev_device->action = strdup(action);
775 if (udev_device->action == NULL)
776 return -ENOMEM;
777 return 0;
778}
779
780int device_set_driver(struct udev_device *udev_device, const char *driver)
781{
782 udev_device->driver = strdup(driver);
783 if (udev_device->driver == NULL)
784 return -ENOMEM;
785 return 0;
786}
787
788const char *device_get_devpath_old(struct udev_device *udev_device)
789{
c4f5f942
KS
790 return udev_device->devpath_old;
791}
792
793int device_set_devpath_old(struct udev_device *udev_device, const char *devpath_old)
794{
795 udev_device->devpath_old = strdup(devpath_old);
796 if (udev_device->devpath_old == NULL)
797 return -ENOMEM;
798 return 0;
799}
800
801const char *device_get_physdevpath(struct udev_device *udev_device)
802{
c4f5f942
KS
803 return udev_device->physdevpath;
804}
805
806int device_set_physdevpath(struct udev_device *udev_device, const char *physdevpath)
807{
808 udev_device->physdevpath = strdup(physdevpath);
809 if (udev_device->physdevpath == NULL)
810 return -ENOMEM;
811 return 0;
812}
813
814int device_get_timeout(struct udev_device *udev_device)
815{
c4f5f942
KS
816 return udev_device->timeout;
817}
818
819int device_set_timeout(struct udev_device *udev_device, int timeout)
820{
821 udev_device->timeout = timeout;
822 return 0;
823}
99214844
KS
824int device_get_event_timeout(struct udev_device *udev_device)
825{
826 if (!udev_device->info_loaded)
827 device_load_info(udev_device);
828 return udev_device->event_timeout;
829}
830
831int device_set_event_timeout(struct udev_device *udev_device, int event_timeout)
832{
833 udev_device->event_timeout = event_timeout;
834 return 0;
835}
c4f5f942 836
37372bbc
KS
837int device_set_seqnum(struct udev_device *udev_device, unsigned long long int seqnum)
838{
839 udev_device->seqnum = seqnum;
840 return 0;
841}
842
c4f5f942
KS
843int device_set_devnum(struct udev_device *udev_device, dev_t devnum)
844{
845 udev_device->devnum = devnum;
846 return 0;
847}
6bd1c78a
KS
848
849int device_get_num_fake_partitions(struct udev_device *udev_device)
850{
99214844
KS
851 if (!udev_device->info_loaded)
852 device_load_info(udev_device);
6bd1c78a
KS
853 return udev_device->num_fake_partitions;
854}
855
856int device_set_num_fake_partitions(struct udev_device *udev_device, int num)
857{
858 udev_device->num_fake_partitions = num;
e88a82b5 859 return 0;
6bd1c78a
KS
860}
861
e88a82b5 862int device_get_devlink_priority(struct udev_device *udev_device)
6bd1c78a 863{
99214844
KS
864 if (!udev_device->info_loaded)
865 device_load_info(udev_device);
e88a82b5 866 return udev_device->devlink_priority;
6bd1c78a
KS
867}
868
e88a82b5 869int device_set_devlink_priority(struct udev_device *udev_device, int prio)
6bd1c78a 870{
e88a82b5
KS
871 udev_device->devlink_priority = prio;
872 return 0;
6bd1c78a
KS
873}
874
875int device_get_ignore_remove(struct udev_device *udev_device)
876{
99214844
KS
877 if (!udev_device->info_loaded)
878 device_load_info(udev_device);
6bd1c78a
KS
879 return udev_device->ignore_remove;
880}
881
882int device_set_ignore_remove(struct udev_device *udev_device, int ignore)
883{
e88a82b5
KS
884 udev_device->ignore_remove = ignore;
885 return 0;
6bd1c78a 886}
e88a82b5 887