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