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