chiark / gitweb /
always include config.h from Makefile
[elogind.git] / udev / lib / libudev-enumerate.c
1 /*
2  * libudev - interface to udev device information
3  *
4  * Copyright (C) 2008 Kay Sievers <kay.sievers@vrfy.org>
5  *
6  * This program is free software: you can redistribute it and/or modify
7  * it under the terms of the GNU General Public License as published by
8  * the Free Software Foundation, either version 2 of the License, or
9  * (at your option) any later version.
10  *
11  * This program is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14  * GNU General Public License for more details.
15  *
16  * You should have received a copy of the GNU General Public License
17  * along with this program.  If not, see <http://www.gnu.org/licenses/>.
18  */
19
20 #include <stdio.h>
21 #include <stdlib.h>
22 #include <stddef.h>
23 #include <unistd.h>
24 #include <errno.h>
25 #include <string.h>
26 #include <dirent.h>
27 #include <sys/stat.h>
28
29 #include "libudev.h"
30 #include "libudev-private.h"
31
32 static int devices_scan_subsystem(struct udev *udev,
33                                   const char *basedir, const char *subsystem, const char *subdir,
34                                   struct list_head *device_list)
35 {
36         char path[UTIL_PATH_SIZE];
37         DIR *dir;
38         struct dirent *dent;
39
40         util_strlcpy(path, udev_get_sys_path(udev), sizeof(path));
41         util_strlcat(path, basedir, sizeof(path));
42         util_strlcat(path, "/", sizeof(path));
43         util_strlcat(path, subsystem, sizeof(path));
44         if (subdir != NULL)
45                 util_strlcat(path, subdir, sizeof(path));
46         dir = opendir(path);
47         if (dir == NULL)
48                 return -1;
49         for (dent = readdir(dir); dent != NULL; dent = readdir(dir)) {
50                 char syspath[UTIL_PATH_SIZE];
51
52                 if (dent->d_name[0] == '.')
53                         continue;
54                 util_strlcpy(syspath, path, sizeof(syspath));
55                 util_strlcat(syspath, "/", sizeof(syspath));
56                 util_strlcat(syspath, dent->d_name, sizeof(syspath));
57                 util_resolve_sys_link(udev, syspath, sizeof(syspath));
58                 util_name_list_add(udev, device_list, syspath, NULL, 1);
59         }
60         closedir(dir);
61         return 0;
62 }
63
64 static int devices_scan_subsystems(struct udev *udev,
65                                    const char *basedir, const char *subsystem, const char *subdir,
66                                    struct list_head *device_list)
67 {
68         char path[UTIL_PATH_SIZE];
69         DIR *dir;
70         struct dirent *dent;
71
72         if (subsystem != NULL)
73                 return devices_scan_subsystem(udev, basedir, subsystem, subdir, device_list);
74
75         util_strlcpy(path, udev_get_sys_path(udev), sizeof(path));
76         util_strlcat(path, basedir, sizeof(path));
77         dir = opendir(path);
78         if (dir == NULL)
79                 return -1;
80         for (dent = readdir(dir); dent != NULL; dent = readdir(dir)) {
81                 if (dent->d_name[0] == '.')
82                         continue;
83                 devices_scan_subsystem(udev, basedir, dent->d_name, subdir, device_list);
84         }
85         closedir(dir);
86         return 0;
87 }
88
89 static int devices_delay(struct udev *udev, const char *syspath)
90 {
91         static const char *delay_device_list[] = {
92                 "/block/md",
93                 "/block/dm-",
94                 NULL
95         };
96         size_t len;
97         int i;
98
99         len = strlen(udev_get_sys_path(udev));
100
101         for (i = 0; delay_device_list[i] != NULL; i++) {
102                 if (strstr(&syspath[len], delay_device_list[i]) != NULL) {
103                         info(udev, "delaying: %s\n", syspath);
104                         return 1;
105                 }
106         }
107         return 0;
108 }
109
110 /**
111  * udev_enumerate_devices:
112  * @udev: udev library context
113  * @subsystem: the subsystem to enumerate
114  * @cb: function to be called for every device found
115  * @data: data to be passed to the function
116  *
117  * Returns: the number of devices passed to the caller, or a negative value on error
118  **/
119 int udev_enumerate_devices(struct udev *udev, const char *subsystem,
120                            int (*cb)(struct udev_device *udev_device, void *data),
121                            void *data)
122 {
123         char base[UTIL_PATH_SIZE];
124         struct stat statbuf;
125         struct list_head device_list;
126         struct util_name_entry *loop_device;
127         struct util_name_entry *tmp_device;
128         int cb_rc = 0;
129         int count = 0;
130
131         INIT_LIST_HEAD(&device_list);
132
133         /* if we have /sys/subsystem/, forget all the old stuff */
134         util_strlcpy(base, udev_get_sys_path(udev), sizeof(base));
135         util_strlcat(base, "/subsystem", sizeof(base));
136         if (stat(base, &statbuf) == 0) {
137                 devices_scan_subsystems(udev, "/subsystem", subsystem, "/devices", &device_list);
138         } else {
139                 devices_scan_subsystems(udev, "/bus", subsystem, "/devices", &device_list);
140                 devices_scan_subsystems(udev, "/class", subsystem, NULL, &device_list);
141         }
142
143         list_for_each_entry_safe(loop_device, tmp_device, &device_list, node) {
144                 if (devices_delay(udev, loop_device->name))
145                         continue;
146                 if (cb_rc == 0) {
147                         struct udev_device *device;
148
149                         device = udev_device_new_from_syspath(udev, loop_device->name);
150                         if (device != NULL) {
151                                 cb_rc = cb(device, data);
152                                 count++;
153                                 udev_device_unref(device);
154                         }
155                 }
156                 list_del(&loop_device->node);
157                 free(loop_device->name);
158                 free(loop_device);
159         }
160
161         /* handle remaining delayed devices */
162         list_for_each_entry_safe(loop_device, tmp_device, &device_list, node) {
163                 if (cb_rc == 0) {
164                         struct udev_device *device;
165
166                         device = udev_device_new_from_syspath(udev, loop_device->name);
167                         if (device != NULL) {
168                                 cb_rc = cb(device, data);
169                                 count++;
170                                 udev_device_unref(device);
171                         }
172                 }
173                 list_del(&loop_device->node);
174                 free(loop_device->name);
175                 free(loop_device);
176         }
177
178         return count;
179 }