chiark / gitweb /
8103c7fcc46448c5812a5a393afa8217c9b83d7f
[elogind.git] / udev / lib / libudev-device.c
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
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>
27 #include <fcntl.h>
28 #include <sys/stat.h>
29
30 #include "libudev.h"
31 #include "libudev-private.h"
32
33 struct udev_device {
34         int refcount;
35         struct udev *udev;
36         struct udev_device *parent_device;
37         char *syspath;
38         const char *devpath;
39         const char *sysname;
40         char *devname;
41         char *subsystem;
42         struct list_head link_list;
43         struct list_head env_list;
44         char *action;
45         char *driver;
46         char *devpath_old;
47         char *physdevpath;
48         int timeout;
49         dev_t devnum;
50         unsigned long long int seqnum;
51         int num_fake_partitions;
52         int devlink_priority;
53         int ignore_remove;
54         struct list_head attr_list;
55 };
56
57 static size_t syspath_to_db_path(struct udev_device *udev_device, char *filename, size_t len)
58 {
59         size_t start;
60
61         /* translate to location of db file */
62         util_strlcpy(filename, udev_get_dev_path(udev_device->udev), len);
63         start = util_strlcat(filename, "/.udev/db/", len);
64         util_strlcat(filename, udev_device->devpath, len);
65         return util_path_encode(&filename[start], len - start);
66 }
67
68 static int device_read_db(struct udev_device *udev_device)
69 {
70         struct stat stats;
71         char filename[UTIL_PATH_SIZE];
72         char line[UTIL_LINE_SIZE];
73         FILE *f;
74         int rc = 0;
75
76         syspath_to_db_path(udev_device, filename, sizeof(filename));
77
78         if (lstat(filename, &stats) != 0) {
79                 info(udev_device->udev, "no db file to read %s: %s\n", filename, strerror(errno));
80                 return -1;
81         }
82         if ((stats.st_mode & S_IFMT) == S_IFLNK) {
83                 char target[UTIL_PATH_SIZE];
84                 int target_len;
85
86                 info(udev_device->udev, "found a symlink as db file\n");
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                 }
94                 dbg(udev_device->udev, "db link points to '%s'\n", target);
95                 if (asprintf(&udev_device->devname, "%s/%s", udev_get_dev_path(udev_device->udev), target) < 0)
96                         return -ENOMEM;
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;
108                 unsigned int maj, min;
109
110                 len = strlen(line);
111                 if (len < 4)
112                         break;
113                 line[len-1] = '\0';
114                 val = &line[2];
115
116                 switch(line[0]) {
117                 case 'N':
118                         asprintf(&udev_device->devname, "%s/%s", udev_get_dev_path(udev_device->udev), val);
119                         break;
120                 case 'M':
121                         sscanf(val, "%u:%u", &maj, &min);
122                         device_set_devnum(udev_device, makedev(maj, min));
123                         break;
124                 case 'S':
125                         util_strlcpy(filename, udev_get_dev_path(udev_device->udev), sizeof(filename));
126                         util_strlcat(filename, "/", sizeof(filename));
127                         util_strlcat(filename, val, sizeof(filename));
128                         device_add_devlink(udev_device, filename);
129                         break;
130                 case 'L':
131                         device_set_devlink_priority(udev_device, atoi(val));
132                         break;
133                 case 'T':
134                         device_set_timeout(udev_device,  atoi(val));
135                         break;
136                 case 'A':
137                         device_set_num_fake_partitions(udev_device, atoi(val));
138                         break;
139                 case 'R':
140                         device_set_ignore_remove(udev_device, atoi(val));
141                         break;
142                 case 'E':
143                         device_add_property_from_string(udev_device, val);
144                         break;
145                 }
146         }
147         fclose(f);
148
149         return rc;
150 }
151
152 struct udev_device *device_init(struct udev *udev)
153 {
154         struct udev_device *udev_device;
155
156         if (udev == NULL)
157                 return NULL;
158
159         udev_device = malloc(sizeof(struct udev_device));
160         if (udev_device == NULL)
161                 return NULL;
162         memset(udev_device, 0x00, sizeof(struct udev_device));
163         udev_device->refcount = 1;
164         udev_device->udev = udev;
165         INIT_LIST_HEAD(&udev_device->link_list);
166         INIT_LIST_HEAD(&udev_device->env_list);
167         INIT_LIST_HEAD(&udev_device->attr_list);
168         info(udev_device->udev, "udev_device: %p created\n", udev_device);
169         return udev_device;
170 }
171
172 /**
173  * udev_device_new_from_syspath:
174  * @udev: udev library context
175  * @syspath: sys device path including sys directory
176  *
177  * Create new udev device, and fill in information from the sys
178  * device and the udev database entry. The sypath is the absolute
179  * path to the device, including the sys mount point.
180  *
181  * The initial refcount is 1, and needs to be decremented to
182  * release the ressources of the udev device.
183  *
184  * Returns: a new udev device, or #NULL, if it does not exist
185  **/
186 struct udev_device *udev_device_new_from_syspath(struct udev *udev, const char *syspath)
187 {
188         char path[UTIL_PATH_SIZE];
189         struct stat statbuf;
190         struct udev_device *udev_device;
191
192         if (udev == NULL)
193                 return NULL;
194         if (syspath == NULL)
195                 return NULL;
196
197         util_strlcpy(path, syspath, sizeof(path));
198         util_strlcat(path, "/uevent", sizeof(path));
199         if (stat(path, &statbuf) != 0) {
200                 info(udev, "not a device :%s\n", syspath);
201                 return NULL;
202         }
203
204         udev_device = device_init(udev);
205         if (udev_device == NULL)
206                 return NULL;
207
208         /* resolve possible symlink to real path */
209         util_strlcpy(path, syspath, sizeof(path));
210         util_resolve_sys_link(udev, path, sizeof(path));
211         device_set_syspath(udev_device, path);
212         info(udev, "device %p has devpath '%s'\n", udev_device, udev_device_get_devpath(udev_device));
213
214         if (device_read_db(udev_device) >= 0)
215                 info(udev, "device %p filled with udev database data\n", udev_device);
216         return udev_device;
217 }
218
219 struct udev_device *udev_device_new_from_devnum(struct udev *udev, char type, dev_t devnum)
220 {
221         char path[UTIL_PATH_SIZE];
222
223         snprintf(path, sizeof(path), "%s/dev/%s/%u:%u",
224                  udev_get_sys_path(udev),
225                  type == 'b' ? "block" : "char",
226                  major(devnum), minor(devnum));
227         if (util_resolve_sys_link(udev, path, sizeof(path)) < 0)
228                 return NULL;
229
230         return udev_device_new_from_syspath(udev, path);
231 }
232
233 static struct udev_device *device_new_from_parent(struct udev_device *udev_device)
234 {
235         struct udev_device *udev_device_parent = NULL;
236         char path[UTIL_PATH_SIZE];
237         char *pos;
238
239         if (udev_device == NULL)
240                 return NULL;
241
242         util_strlcpy(path, udev_device->syspath, sizeof(path));
243         while (1) {
244                 pos = strrchr(path, '/');
245                 if (pos == path || pos == NULL)
246                         break;
247                 pos[0] = '\0';
248                 udev_device_parent = udev_device_new_from_syspath(udev_device->udev, path);
249                 if (udev_device_parent != NULL)
250                         return udev_device_parent;
251         }
252
253         /* follow "device" link in deprecated sys /sys/class/ layout */
254         if (strncmp(udev_device->devpath, "/class/", 7) == 0) {
255                 util_strlcpy(path, udev_device->syspath, sizeof(path));
256                 util_strlcat(path, "/device", sizeof(path));
257                 if (util_resolve_sys_link(udev_device->udev, path, sizeof(path)) == 0) {
258                         udev_device_parent = udev_device_new_from_syspath(udev_device->udev, path);
259                         if (udev_device_parent != NULL)
260                                 return udev_device_parent;
261                 }
262         }
263         return NULL;
264 }
265
266 struct udev_device *udev_device_get_parent(struct udev_device *udev_device)
267 {
268         if (udev_device->parent_device != NULL) {
269                 info(udev_device->udev, "returning existing parent %p\n", udev_device->parent_device);
270                 return udev_device->parent_device;
271         }
272         udev_device->parent_device = device_new_from_parent(udev_device);
273         return udev_device->parent_device;
274 }
275
276 /**
277  * udev_device_get_udev:
278  * @udev_device: udev device
279  *
280  * Retrieve the udev library context the device was created with.
281  *
282  * Returns: the udev library context
283  **/
284 struct udev *udev_device_get_udev(struct udev_device *udev_device)
285 {
286         if (udev_device == NULL)
287                 return NULL;
288         return udev_device->udev;
289 }
290
291 /**
292  * udev_device_ref:
293  * @udev_device: udev device
294  *
295  * Take a reference of a udev device.
296  *
297  * Returns: the passed udev device
298  **/
299 struct udev_device *udev_device_ref(struct udev_device *udev_device)
300 {
301         if (udev_device == NULL)
302                 return NULL;
303         udev_device->refcount++;
304         return udev_device;
305 }
306
307 /**
308  * udev_device_unref:
309  * @udev_device: udev device
310  *
311  * Drop a reference of a udev device. If the refcount reaches zero,
312  * the ressources of the device will be released.
313  *
314  **/
315 void udev_device_unref(struct udev_device *udev_device)
316 {
317         if (udev_device == NULL)
318                 return;
319         udev_device->refcount--;
320         if (udev_device->refcount > 0)
321                 return;
322         if (udev_device->parent_device != NULL)
323                 udev_device_unref(udev_device->parent_device);
324         free(udev_device->syspath);
325         free(udev_device->devname);
326         free(udev_device->subsystem);
327         util_name_list_cleanup(udev_device->udev, &udev_device->link_list);
328         util_name_list_cleanup(udev_device->udev, &udev_device->env_list);
329         free(udev_device->action);
330         free(udev_device->driver);
331         free(udev_device->devpath_old);
332         free(udev_device->physdevpath);
333         util_name_list_cleanup(udev_device->udev, &udev_device->attr_list);
334         info(udev_device->udev, "udev_device: %p released\n", udev_device);
335         free(udev_device);
336 }
337
338 /**
339  * udev_device_get_devpath:
340  * @udev_device: udev device
341  *
342  * Retrieve the kernel devpath value of the udev device. The path
343  * does not contain the sys mount point, and starts with a '/'.
344  *
345  * Returns: the devpath of the udev device
346  **/
347 const char *udev_device_get_devpath(struct udev_device *udev_device)
348 {
349         if (udev_device == NULL)
350                 return NULL;
351         return udev_device->devpath;
352 }
353
354 /**
355  * udev_device_get_syspath:
356  * @udev_device: udev device
357  *
358  * Retrieve the sys path of the udev device. The path is an
359  * absolute path and starts with the sys mount point.
360  *
361  * Returns: the sys path of the udev device
362  **/
363 const char *udev_device_get_syspath(struct udev_device *udev_device)
364 {
365         if (udev_device == NULL)
366                 return NULL;
367         return udev_device->syspath;
368 }
369
370 const char *udev_device_get_sysname(struct udev_device *udev_device)
371 {
372         if (udev_device == NULL)
373                 return NULL;
374         return udev_device->sysname;
375 }
376
377 /**
378  * udev_device_get_devnode:
379  * @udev_device: udev device
380  *
381  * Retrieve the device node file name belonging to the udev device.
382  * The path is an absolute path, and starts with the device directory.
383  *
384  * Returns: the device node file name of the udev device, or #NULL if no device node exists
385  **/
386 const char *udev_device_get_devnode(struct udev_device *udev_device)
387 {
388         if (udev_device == NULL)
389                 return NULL;
390         return udev_device->devname;
391 }
392
393 /**
394  * udev_device_get_subsystem:
395  * @udev_device: udev device
396  *
397  * Retrieve the subsystem string of the udev device. The string does not
398  * contain any "/".
399  *
400  * Returns: the subsystem name of the udev device, or #NULL if it can not be determined
401  **/
402 const char *udev_device_get_subsystem(struct udev_device *udev_device)
403 {
404         char subsystem[UTIL_NAME_SIZE];
405
406         if (udev_device == NULL)
407                 return NULL;
408         if (udev_device->subsystem != NULL)
409                 return udev_device->subsystem;
410
411         /* read "subsytem" link */
412         if (util_get_sys_subsystem(udev_device->udev, udev_device->syspath, subsystem, sizeof(subsystem)) > 0) {
413                 udev_device->subsystem = strdup(subsystem);
414                 return udev_device->subsystem;
415         }
416
417         /* implicit names */
418         if (strncmp(udev_device->devpath, "/module/", 8) == 0) {
419                 udev_device->subsystem = strdup("module");
420                 return udev_device->subsystem;
421         }
422         if (strstr(udev_device->devpath, "/drivers/") != NULL) {
423                 udev_device->subsystem = strdup("drivers");
424                 return udev_device->subsystem;
425         }
426         if (strncmp(udev_device->devpath, "/subsystem/", 11) == 0 ||
427             strncmp(udev_device->devpath, "/class/", 7) == 0 ||
428             strncmp(udev_device->devpath, "/bus/", 5) == 0) {
429                 udev_device->subsystem = strdup("subsystem");
430                 return udev_device->subsystem;
431         }
432         return NULL;
433 }
434
435 /**
436  * udev_device_get_devlinks:
437  * @udev_device: udev device
438  * @cb: function to be called for every device link found
439  * @data: data to be passed to the function
440  *
441  * Retrieve the device links pointing to the device file of the
442  * udev device. For every device link, the passed function will be
443  * called with the device link string.
444  * The path is an absolute path, and starts with the device directory.
445  * If the function returns 1, remaning device links will be ignored.
446  *
447  * Returns: the number of device links passed to the caller, or a negative value on error
448  **/
449 int udev_device_get_devlinks(struct udev_device *udev_device,
450                               int (*cb)(struct udev_device *udev_device, const char *value, void *data),
451                               void *data)
452 {
453         struct util_name_entry *name_loop;
454         int count = 0;
455
456         if (udev_device == NULL)
457                 return -1;
458         list_for_each_entry(name_loop, &udev_device->link_list, node) {
459                 count++;
460                 if (cb(udev_device, name_loop->name, data) != 0)
461                         break;
462         }
463         return count;
464 }
465
466 /**
467  * udev_device_get_properties:
468  * @udev_device: udev device
469  * @cb: function to be called for every property found
470  * @data: data to be passed to the function
471  *
472  * Retrieve the property key/value pairs belonging to the
473  * udev device. For every key/value pair, the passed function will be
474  * called. If the function returns 1, remaning properties will be
475  * ignored.
476  *
477  * Returns: the number of properties passed to the caller, or a negative value on error
478  **/
479 int udev_device_get_properties(struct udev_device *udev_device,
480                                 int (*cb)(struct udev_device *udev_device, const char *key, const char *value, void *data),
481                                 void *data)
482 {
483         struct util_name_entry *name_loop;
484         int count = 0;
485
486         if (udev_device == NULL)
487                 return -1;
488         list_for_each_entry(name_loop, &udev_device->env_list, node) {
489                 count++;
490                 if (cb(udev_device, name_loop->name, name_loop->value, data) != 0)
491                         break;
492         }
493         return count;
494 }
495
496 const char *udev_device_get_driver(struct udev_device *udev_device)
497 {
498         char driver[UTIL_NAME_SIZE];
499
500         if (udev_device == NULL)
501                 return NULL;
502         if (udev_device->driver != NULL)
503                 return udev_device->driver;
504         if (util_get_sys_driver(udev_device->udev, udev_device->syspath, driver, sizeof(driver)) < 2)
505                 return NULL;
506         udev_device->driver = strdup(driver);
507         return udev_device->driver;
508 }
509
510 dev_t udev_device_get_devnum(struct udev_device *udev_device)
511 {
512         if (udev_device == NULL)
513                 return makedev(0, 0);
514         return udev_device->devnum;
515 }
516
517 const char *udev_device_get_action(struct udev_device *udev_device)
518 {
519         if (udev_device == NULL)
520                 return NULL;
521         return udev_device->action;
522 }
523
524 unsigned long long int udev_device_get_seqnum(struct udev_device *udev_device)
525 {
526         if (udev_device == NULL)
527                 return 0;
528         return udev_device->seqnum;
529 }
530
531 const char *udev_device_get_attr_value(struct udev_device *udev_device, const char *attr)
532 {
533         struct util_name_entry *name_loop;
534         char path[UTIL_PATH_SIZE];
535         char value[UTIL_NAME_SIZE];
536         struct stat statbuf;
537         int fd;
538         ssize_t size;
539         const char *val = NULL;
540
541         /* look for possibly already cached result */
542         list_for_each_entry(name_loop, &udev_device->attr_list, node) {
543                 if (strcmp(name_loop->name, attr) == 0) {
544                         info(udev_device->udev, "'%s' in cache '%s'\n", attr, name_loop->value);
545                         return name_loop->value;
546                 }
547         }
548
549         util_strlcpy(path, udev_device_get_syspath(udev_device), sizeof(path));
550         util_strlcat(path, "/", sizeof(path));
551         util_strlcat(path, attr, sizeof(path));
552
553         if (lstat(path, &statbuf) != 0) {
554                 info(udev_device->udev, "stat '%s' failed: %s\n", path, strerror(errno));
555                 goto out;
556         }
557
558         if (S_ISLNK(statbuf.st_mode)) {
559                 /* links return the last element of the target path */
560                 char target[UTIL_NAME_SIZE];
561                 int len;
562                 char *pos;
563
564                 len = readlink(path, target, sizeof(target));
565                 if (len > 0) {
566                         target[len] = '\0';
567                         pos = strrchr(target, '/');
568                         if (pos != NULL) {
569                                 pos = &pos[1];
570                                 info(udev_device->udev, "cache '%s' with link value '%s'\n", attr, pos);
571                                 val = util_name_list_add(udev_device->udev, &udev_device->attr_list, attr, pos, 0)->value;
572                         }
573                 }
574                 goto out;
575         }
576
577         /* skip directories */
578         if (S_ISDIR(statbuf.st_mode))
579                 goto out;
580
581         /* skip non-readable files */
582         if ((statbuf.st_mode & S_IRUSR) == 0)
583                 goto out;
584
585         /* read attribute value */
586         fd = open(path, O_RDONLY);
587         if (fd < 0) {
588                 info(udev_device->udev, "attribute '%s' can not be opened\n", path);
589                 goto out;
590         }
591         size = read(fd, value, sizeof(value));
592         close(fd);
593         if (size < 0)
594                 goto out;
595         if (size == sizeof(value))
596                 goto out;
597
598         /* got a valid value, store it in cache and return it */
599         value[size] = '\0';
600         util_remove_trailing_chars(value, '\n');
601         info(udev_device->udev, "'%s' has attribute value '%s'\n", path, value);
602         val = util_name_list_add(udev_device->udev, &udev_device->attr_list, attr, value, 0)->value;
603 out:
604         return val;
605 }
606 int device_set_syspath(struct udev_device *udev_device, const char *syspath)
607 {
608         const char *pos;
609
610         udev_device->syspath = strdup(syspath);
611         if (udev_device->syspath ==  NULL)
612                 return -ENOMEM;
613         udev_device->devpath = &udev_device->syspath[strlen(udev_get_sys_path(udev_device->udev))];
614         pos = strrchr(udev_device->syspath, '/');
615         if (pos == NULL)
616                 return -EINVAL;
617         udev_device->sysname = &pos[1];
618         return 0;
619 }
620
621 int device_set_subsystem(struct udev_device *udev_device, const char *subsystem)
622 {
623         udev_device->subsystem = strdup(subsystem);
624         if (udev_device->subsystem == NULL)
625                 return -1;
626         return 0;
627 }
628
629 int device_set_devname(struct udev_device *udev_device, const char *devname)
630 {
631         udev_device->devname = strdup(devname);
632         if (udev_device->devname == NULL)
633                 return -ENOMEM;
634         return 0;
635 }
636
637 int device_add_devlink(struct udev_device *udev_device, const char *devlink)
638 {
639         if (util_name_list_add(udev_device->udev, &udev_device->link_list, devlink, NULL, 0) == NULL)
640                 return -ENOMEM;
641         return 0;
642 }
643
644 int device_add_property(struct udev_device *udev_device, const char *key, const char *value)
645 {
646         if (util_name_list_add(udev_device->udev, &udev_device->env_list, key, value, 0) == NULL)
647                 return -ENOMEM;
648         return 0;
649 }
650
651 int device_add_property_from_string(struct udev_device *udev_device, const char *property)
652 {
653         char name[UTIL_PATH_SIZE];
654         char *val;
655
656         strncpy(name, property, sizeof(name));
657         val = strchr(name, '=');
658         if (val == NULL)
659                 return -1;
660         val[0] = '\0';
661         val = &val[1];
662         if (val[0] == '\0')
663                 val = NULL;
664         device_add_property(udev_device, name, val);
665         return 0;
666 }
667
668 int device_set_action(struct udev_device *udev_device, const char *action)
669 {
670         udev_device->action = strdup(action);
671         if (udev_device->action == NULL)
672                 return -ENOMEM;
673         return 0;
674 }
675
676 int device_set_driver(struct udev_device *udev_device, const char *driver)
677 {
678         udev_device->driver = strdup(driver);
679         if (udev_device->driver == NULL)
680                 return -ENOMEM;
681         return 0;
682 }
683
684 const char *device_get_devpath_old(struct udev_device *udev_device)
685 {
686         if (udev_device == NULL)
687                 return NULL;
688         return udev_device->devpath_old;
689 }
690
691 int device_set_devpath_old(struct udev_device *udev_device, const char *devpath_old)
692 {
693         udev_device->devpath_old = strdup(devpath_old);
694         if (udev_device->devpath_old == NULL)
695                 return -ENOMEM;
696         return 0;
697 }
698
699 const char *device_get_physdevpath(struct udev_device *udev_device)
700 {
701         if (udev_device == NULL)
702                 return NULL;
703         return udev_device->physdevpath;
704 }
705
706 int device_set_physdevpath(struct udev_device *udev_device, const char *physdevpath)
707 {
708         udev_device->physdevpath = strdup(physdevpath);
709         if (udev_device->physdevpath == NULL)
710                 return -ENOMEM;
711         return 0;
712 }
713
714 int device_get_timeout(struct udev_device *udev_device)
715 {
716         if (udev_device == NULL)
717                 return -1;
718         return udev_device->timeout;
719 }
720
721 int device_set_timeout(struct udev_device *udev_device, int timeout)
722 {
723         udev_device->timeout = timeout;
724         return 0;
725 }
726
727 int device_set_seqnum(struct udev_device *udev_device, unsigned long long int seqnum)
728 {
729         udev_device->seqnum = seqnum;
730         return 0;
731 }
732
733 int device_set_devnum(struct udev_device *udev_device, dev_t devnum)
734 {
735         udev_device->devnum = devnum;
736         return 0;
737 }
738
739 int device_get_num_fake_partitions(struct udev_device *udev_device)
740 {
741         if (udev_device == NULL)
742                 return -1;
743         return udev_device->num_fake_partitions;
744 }
745
746 int device_set_num_fake_partitions(struct udev_device *udev_device, int num)
747 {
748         udev_device->num_fake_partitions = num;
749         return 0;
750 }
751
752 int device_get_devlink_priority(struct udev_device *udev_device)
753 {
754         if (udev_device == NULL)
755                 return -1;
756         return udev_device->devlink_priority;
757 }
758
759 int device_set_devlink_priority(struct udev_device *udev_device, int prio)
760 {
761          udev_device->devlink_priority = prio;
762         return 0;
763 }
764
765 int device_get_ignore_remove(struct udev_device *udev_device)
766 {
767         if (udev_device == NULL)
768                 return -1;
769         return udev_device->ignore_remove;
770 }
771
772 int device_set_ignore_remove(struct udev_device *udev_device, int ignore)
773 {
774         udev_device->ignore_remove = ignore;
775         return 0;
776 }
777