chiark / gitweb /
78b644b01d8252a638a64a8690e4d191cbd1d9c5
[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 <sys/stat.h>
30
31 #include "libudev.h"
32 #include "libudev-private.h"
33 #include "../udev.h"
34
35 struct udev_device {
36         int refcount;
37         struct udev *udev;
38         char *devpath;
39         char *syspath;
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 };
55
56 static size_t devpath_to_db_path(struct udev *udev, const char *devpath, char *filename, size_t len)
57 {
58         size_t start;
59
60         /* translate to location of db file */
61         strlcpy(filename, udev_get_dev_path(udev), len);
62         start = strlcat(filename, "/.udev/db/", len);
63         strlcat(filename, devpath, len);
64         return util_path_encode(&filename[start], len - start);
65 }
66
67 static int device_read_db(struct udev_device *udev_device)
68 {
69         struct stat stats;
70         char filename[PATH_SIZE];
71         char line[PATH_SIZE];
72         FILE *f;
73         int rc = 0;
74
75         devpath_to_db_path(udev_device->udev, udev_device->devpath, filename, sizeof(filename));
76
77         if (lstat(filename, &stats) != 0) {
78                 info(udev_device->udev, "no db file to read %s: %s\n", filename, strerror(errno));
79                 return -1;
80         }
81         if ((stats.st_mode & S_IFMT) == S_IFLNK) {
82                 char target[NAME_SIZE];
83                 int target_len;
84
85                 info(udev_device->udev, "found a symlink as db file\n");
86                 target_len = readlink(filename, target, sizeof(target));
87                 if (target_len > 0)
88                         target[target_len] = '\0';
89                 else {
90                         info(udev_device->udev, "error reading db link %s: %s\n", filename, strerror(errno));
91                         return -1;
92                 }
93                 dbg(udev_device->udev, "db link points to '%s'\n", target);
94                 if (asprintf(&udev_device->devname, "%s/%s", udev_get_dev_path(udev_device->udev), target) < 0)
95                         return -ENOMEM;
96                 return 0;
97         }
98
99         f = fopen(filename, "r");
100         if (f == NULL) {
101                 info(udev_device->udev, "error reading db file %s: %s\n", filename, strerror(errno));
102                 return -1;
103         }
104         while (fgets(line, sizeof(line), f)) {
105                 ssize_t len;
106                 const char *val;
107                 unsigned int maj, min;
108
109                 len = strlen(line);
110                 if (len < 4)
111                         break;
112                 line[len-1] = '\0';
113                 val = &line[2];
114
115                 switch(line[0]) {
116                 case 'N':
117                         asprintf(&udev_device->devname, "%s/%s", udev_get_dev_path(udev_device->udev), val);
118                         break;
119                 case 'M':
120                         sscanf(val, "%u:%u", &maj, &min);
121                         device_set_devnum(udev_device, makedev(maj, min));
122                         break;
123                 case 'S':
124                         strlcpy(filename, udev_get_dev_path(udev_device->udev), sizeof(filename));
125                         strlcat(filename, "/", sizeof(filename));
126                         strlcat(filename, val, sizeof(filename));
127                         device_add_devlink(udev_device, filename);
128                         break;
129                 case 'L':
130                         device_set_devlink_priority(udev_device, atoi(val));
131                         break;
132                 case 'T':
133                         device_set_timeout(udev_device,  atoi(val));
134                         break;
135                 case 'A':
136                         device_set_num_fake_partitions(udev_device, atoi(val));
137                         break;
138                 case 'R':
139                         device_set_ignore_remove(udev_device, atoi(val));
140                         break;
141                 case 'E':
142                         device_add_property(udev_device, val);
143                         break;
144                 }
145         }
146         fclose(f);
147
148         return rc;
149 }
150
151 struct udev_device *device_init(struct udev *udev)
152 {
153         struct udev_device *udev_device;
154
155         if (udev == NULL)
156                 return NULL;
157
158         udev_device = malloc(sizeof(struct udev_device));
159         if (udev_device == NULL)
160                 return NULL;
161         memset(udev_device, 0x00, sizeof(struct udev_device));
162         udev_device->refcount = 1;
163         udev_device->udev = udev;
164         INIT_LIST_HEAD(&udev_device->link_list);
165         INIT_LIST_HEAD(&udev_device->env_list);
166         info(udev_device->udev, "udev_device: %p created\n", udev_device);
167         return udev_device;
168 }
169
170 /**
171  * udev_device_new_from_devpath:
172  * @udev: udev library context
173  * @devpath: sys device path
174  *
175  * Create new udev device, and fill in information from the sysfs
176  * device and the udev database entry. The devpath must not contain
177  * the sysfs mount path, and must contain a leading '/'.
178  *
179  * The initial refcount is 1, and needs to be decremented to
180  * release the ressources of the udev device.
181  *
182  * Returns: a new udev device, or #NULL, if it does not exist
183  **/
184 struct udev_device *udev_device_new_from_devpath(struct udev *udev, const char *devpath)
185 {
186         char path[PATH_SIZE];
187         struct stat statbuf;
188         struct udev_device *udev_device;
189
190         if (udev == NULL)
191                 return NULL;
192         if (devpath == NULL)
193                 return NULL;
194
195         strlcpy(path, udev_get_sys_path(udev), sizeof(path));
196         strlcat(path, devpath, sizeof(path));
197         if (stat(path, &statbuf) != 0)
198                 return NULL;
199         if (!S_ISDIR(statbuf.st_mode))
200                 return NULL;
201
202         udev_device = device_init(udev);
203         if (udev_device == NULL)
204                 return NULL;
205
206         /* resolve possible symlink to real path */
207         strlcpy(path, devpath, sizeof(path));
208         util_resolve_sys_link(udev, path, sizeof(path));
209         device_set_devpath(udev_device, path);
210         info(udev, "device %p has devpath '%s'\n", udev_device, udev_device_get_devpath(udev_device));
211
212         if (device_read_db(udev_device) >= 0)
213                 info(udev, "device %p filled with udev database data\n", udev_device);
214
215         return udev_device;
216 }
217
218 /**
219  * udev_device_get_udev:
220  * @udev_device: udev device
221  *
222  * Retrieve the udev library context the device was created with.
223  *
224  * Returns: the udev library context
225  **/
226 struct udev *udev_device_get_udev(struct udev_device *udev_device)
227 {
228         if (udev_device == NULL)
229                 return NULL;
230         return udev_device->udev;
231 }
232
233 /**
234  * udev_device_ref:
235  * @udev_device: udev device
236  *
237  * Take a reference of a udev device.
238  *
239  * Returns: the passed udev device
240  **/
241 struct udev_device *udev_device_ref(struct udev_device *udev_device)
242 {
243         if (udev_device == NULL)
244                 return NULL;
245         udev_device->refcount++;
246         return udev_device;
247 }
248
249 /**
250  * udev_device_unref:
251  * @udev_device: udev device
252  *
253  * Drop a reference of a udev device. If the refcount reaches zero,
254  * the ressources of the device will be released.
255  *
256  **/
257 void udev_device_unref(struct udev_device *udev_device)
258 {
259         if (udev_device == NULL)
260                 return;
261         udev_device->refcount--;
262         if (udev_device->refcount > 0)
263                 return;
264         free(udev_device->syspath);
265         free(udev_device->devname);
266         free(udev_device->subsystem);
267         util_name_list_cleanup(udev_device->udev, &udev_device->link_list);
268         util_name_list_cleanup(udev_device->udev, &udev_device->env_list);
269         free(udev_device->action);
270         free(udev_device->driver);
271         free(udev_device->devpath_old);
272         free(udev_device->physdevpath);
273         info(udev_device->udev, "udev_device: %p released\n", udev_device);
274         free(udev_device);
275 }
276
277 /**
278  * udev_device_get_devpath:
279  * @udev_device: udev device
280  *
281  * Retrieve the kernel devpath value of the udev device. The path
282  * does not contain the sys mount point, and starts with a '/'.
283  *
284  * Returns: the devpath of the udev device
285  **/
286 const char *udev_device_get_devpath(struct udev_device *udev_device)
287 {
288         if (udev_device == NULL)
289                 return NULL;
290         return udev_device->devpath;
291 }
292
293 /**
294  * udev_device_get_syspath:
295  * @udev_device: udev device
296  *
297  * Retrieve the sys path of the udev device. The path is an
298  * absolute path and starts with the sys mount point.
299  *
300  * Returns: the sys path of the udev device
301  **/
302 const char *udev_device_get_syspath(struct udev_device *udev_device)
303 {
304         if (udev_device == NULL)
305                 return NULL;
306         return udev_device->syspath;
307 }
308
309 /**
310  * udev_device_get_devname:
311  * @udev_device: udev device
312  *
313  * Retrieve the device node file name belonging to the udev device.
314  * The path is an absolute path, and starts with the device directory.
315  *
316  * Returns: the device node file name of the udev device, or #NULL if no device node exists
317  **/
318 const char *udev_device_get_devname(struct udev_device *udev_device)
319 {
320         if (udev_device == NULL)
321                 return NULL;
322         return udev_device->devname;
323 }
324
325 /**
326  * udev_device_get_subsystem:
327  * @udev_device: udev device
328  *
329  * Retrieve the subsystem string of the udev device. The string does not
330  * contain any "/".
331  *
332  * Returns: the subsystem name of the udev device, or #NULL if it can not be determined
333  **/
334 const char *udev_device_get_subsystem(struct udev_device *udev_device)
335 {
336         char subsystem[NAME_SIZE];
337
338         if (udev_device == NULL)
339                 return NULL;
340         if (udev_device->subsystem != NULL)
341                 return udev_device->subsystem;
342         if (util_get_sys_subsystem(udev_device->udev, udev_device->devpath, subsystem, sizeof(subsystem)) < 2)
343                 return NULL;
344         udev_device->subsystem = strdup(subsystem);
345         return udev_device->subsystem;
346 }
347
348 /**
349  * udev_device_get_devlinks:
350  * @udev_device: udev device
351  * @cb: function to be called for every device link found
352  * @data: data to be passed to the function
353  *
354  * Retrieve the device links pointing to the device file of the
355  * udev device. For every device link, the passed function will be
356  * called with the device link string.
357  * The path is an absolute path, and starts with the device directory.
358  * If the function returns 1, remaning device links will be ignored.
359  *
360  * Returns: the number of device links passed to the caller, or a negative value on error
361  **/
362 int udev_device_get_devlinks(struct udev_device *udev_device,
363                               int (*cb)(struct udev_device *udev_device, const char *value, void *data),
364                               void *data)
365 {
366         struct name_entry *name_loop;
367         int count = 0;
368
369         if (udev_device == NULL)
370                 return -1;
371         list_for_each_entry(name_loop, &udev_device->link_list, node) {
372                 count++;
373                 if (cb(udev_device, name_loop->name, data) != 0)
374                         break;
375         }
376         return count;
377 }
378
379 /**
380  * udev_device_get_properties:
381  * @udev_device: udev device
382  * @cb: function to be called for every property found
383  * @data: data to be passed to the function
384  *
385  * Retrieve the property key/value pairs belonging to the
386  * udev device. For every key/value pair, the passed function will be
387  * called. If the function returns 1, remaning properties will be
388  * ignored.
389  *
390  * Returns: the number of properties passed to the caller, or a negative value on error
391  **/
392 int udev_device_get_properties(struct udev_device *udev_device,
393                                 int (*cb)(struct udev_device *udev_device, const char *key, const char *value, void *data),
394                                 void *data)
395 {
396         struct name_entry *name_loop;
397         int count = 0;
398
399         if (udev_device == NULL)
400                 return -1;
401         list_for_each_entry(name_loop, &udev_device->env_list, node) {
402                 char name[PATH_SIZE];
403                 char *val;
404
405                 strncpy(name, name_loop->name, PATH_SIZE);
406                 name[PATH_SIZE-1] = '\0';
407                 val = strchr(name, '=');
408                 if (val == NULL)
409                         continue;
410                 val[0] = '\0';
411                 val = &val[1];
412                 count++;
413                 if (cb(udev_device, name, val, data) != 0)
414                         break;
415         }
416         return count;
417 }
418
419 const char *udev_device_get_driver(struct udev_device *udev_device)
420 {
421         char driver[NAME_SIZE];
422
423         if (udev_device == NULL)
424                 return NULL;
425         if (udev_device->driver != NULL)
426                 return udev_device->driver;
427         if (util_get_sys_driver(udev_device->udev, udev_device->devpath, driver, sizeof(driver)) < 2)
428                 return NULL;
429         udev_device->driver = strdup(driver);
430         return udev_device->driver;
431 }
432
433 dev_t udev_device_get_devnum(struct udev_device *udev_device)
434 {
435         if (udev_device == NULL)
436                 return makedev(0, 0);
437         return udev_device->devnum;
438 }
439
440 const char *udev_device_get_action(struct udev_device *udev_device)
441 {
442         if (udev_device == NULL)
443                 return NULL;
444         return udev_device->action;
445 }
446
447 unsigned long long int udev_device_get_seqnum(struct udev_device *udev_device)
448 {
449         if (udev_device == NULL)
450                 return 0;
451         return udev_device->seqnum;
452 }
453
454 int device_set_devpath(struct udev_device *udev_device, const char *devpath)
455 {
456         if (asprintf(&udev_device->syspath, "%s%s", udev_get_sys_path(udev_device->udev), devpath) < 0)
457                 return -ENOMEM;
458         udev_device->devpath = &udev_device->syspath[strlen(udev_get_sys_path(udev_device->udev))];
459         return 0;
460 }
461
462 int device_set_subsystem(struct udev_device *udev_device, const char *subsystem)
463 {
464         udev_device->subsystem = strdup(subsystem);
465         if (udev_device->subsystem == NULL)
466                 return -1;
467         return 0;
468 }
469
470 int device_set_devname(struct udev_device *udev_device, const char *devname)
471 {
472         udev_device->devname = strdup(devname);
473         if (udev_device->devname == NULL)
474                 return -ENOMEM;
475         return 0;
476 }
477
478 int device_add_devlink(struct udev_device *udev_device, const char *devlink)
479 {
480         if (util_name_list_add(udev_device->udev, &udev_device->link_list, devlink, 0) == NULL)
481                 return -ENOMEM;
482         return 0;
483 }
484
485 int device_add_property(struct udev_device *udev_device, const char *property)
486 {
487         if (util_name_list_add(udev_device->udev, &udev_device->env_list, property, 0) == NULL)
488                 return -ENOMEM;
489         return 0;
490 }
491
492 int device_set_action(struct udev_device *udev_device, const char *action)
493 {
494         udev_device->action = strdup(action);
495         if (udev_device->action == NULL)
496                 return -ENOMEM;
497         return 0;
498 }
499
500 int device_set_driver(struct udev_device *udev_device, const char *driver)
501 {
502         udev_device->driver = strdup(driver);
503         if (udev_device->driver == NULL)
504                 return -ENOMEM;
505         return 0;
506 }
507
508 const char *device_get_devpath_old(struct udev_device *udev_device)
509 {
510         if (udev_device == NULL)
511                 return NULL;
512         return udev_device->devpath_old;
513 }
514
515 int device_set_devpath_old(struct udev_device *udev_device, const char *devpath_old)
516 {
517         udev_device->devpath_old = strdup(devpath_old);
518         if (udev_device->devpath_old == NULL)
519                 return -ENOMEM;
520         return 0;
521 }
522
523 const char *device_get_physdevpath(struct udev_device *udev_device)
524 {
525         if (udev_device == NULL)
526                 return NULL;
527         return udev_device->physdevpath;
528 }
529
530 int device_set_physdevpath(struct udev_device *udev_device, const char *physdevpath)
531 {
532         udev_device->physdevpath = strdup(physdevpath);
533         if (udev_device->physdevpath == NULL)
534                 return -ENOMEM;
535         return 0;
536 }
537
538 int device_get_timeout(struct udev_device *udev_device)
539 {
540         if (udev_device == NULL)
541                 return -1;
542         return udev_device->timeout;
543 }
544
545 int device_set_timeout(struct udev_device *udev_device, int timeout)
546 {
547         udev_device->timeout = timeout;
548         return 0;
549 }
550
551 int device_set_seqnum(struct udev_device *udev_device, unsigned long long int seqnum)
552 {
553         udev_device->seqnum = seqnum;
554         return 0;
555 }
556
557 int device_set_devnum(struct udev_device *udev_device, dev_t devnum)
558 {
559         udev_device->devnum = devnum;
560         return 0;
561 }
562
563 int device_get_num_fake_partitions(struct udev_device *udev_device)
564 {
565         if (udev_device == NULL)
566                 return -1;
567         return udev_device->num_fake_partitions;
568 }
569
570 int device_set_num_fake_partitions(struct udev_device *udev_device, int num)
571 {
572         udev_device->num_fake_partitions = num;
573         return 0;
574 }
575
576 int device_get_devlink_priority(struct udev_device *udev_device)
577 {
578         if (udev_device == NULL)
579                 return -1;
580         return udev_device->devlink_priority;
581 }
582
583 int device_set_devlink_priority(struct udev_device *udev_device, int prio)
584 {
585          udev_device->devlink_priority = prio;
586         return 0;
587 }
588
589 int device_get_ignore_remove(struct udev_device *udev_device)
590 {
591         if (udev_device == NULL)
592                 return -1;
593         return udev_device->ignore_remove;
594 }
595
596 int device_set_ignore_remove(struct udev_device *udev_device, int ignore)
597 {
598         udev_device->ignore_remove = ignore;
599         return 0;
600 }
601