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