4 * Copyright (C) 2004-2006 Kay Sievers <kay@vrfy.org>
5 * Copyright (C) 2006 Hannes Reinecke <hare@suse.de>
7 * This program is free software; you can redistribute it and/or modify it
8 * under the terms of the GNU General Public License as published by the
9 * Free Software Foundation version 2 of the License.
11 * This program is distributed in the hope that it will be useful, but
12 * WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * General Public License for more details.
16 * You should have received a copy of the GNU General Public License along
17 * with this program; if not, write to the Free Software Foundation, Inc.,
18 * 675 Mass Ave, Cambridge, MA 02139, USA.
32 #include <sys/types.h>
36 static const char *udev_log_str;
41 void log_message(int priority, const char *format, ...)
45 if (priority > udev_log_priority)
48 va_start(args, format);
49 vsyslog(priority, format, args);
54 /* list of devices that we should run last due to any one of a number of reasons */
55 static char *last_list[] = {
63 /* list of devices that we should run first due to any one of a number of reasons */
64 static char *first_list[] = {
70 LIST_HEAD(device_first_list);
71 LIST_HEAD(device_default_list);
72 LIST_HEAD(device_last_list);
74 static int device_list_insert(const char *path)
76 struct list_head *device_list = &device_default_list;
77 const char *devpath = &path[strlen(sysfs_path)];
80 for (i = 0; first_list[i] != NULL; i++) {
81 if (strncmp(devpath, first_list[i], strlen(first_list[i])) == 0) {
82 device_list = &device_first_list;
86 for (i = 0; last_list[i] != NULL; i++) {
87 if (strncmp(devpath, last_list[i], strlen(last_list[i])) == 0) {
88 device_list = &device_last_list;
93 dbg("add '%s'" , path);
94 /* double entries will be ignored */
95 name_list_add(device_list, path, 0);
99 static void trigger_uevent(const char *path)
101 char filename[PATH_SIZE];
104 strlcpy(filename, path, sizeof(filename));
105 strlcat(filename, "/uevent", sizeof(filename));
108 printf("%s\n", path);
113 fd = open(filename, O_WRONLY);
115 dbg("error on opening %s: %s\n", filename, strerror(errno));
119 if (write(fd, "add", 3) < 0)
120 info("error on triggering %s: %s\n", filename, strerror(errno));
125 static void exec_lists(void)
127 struct name_entry *loop_device;
128 struct name_entry *tmp_device;
130 /* handle the devices on the "first" list first */
131 list_for_each_entry_safe(loop_device, tmp_device, &device_first_list, node) {
132 trigger_uevent(loop_device->name);
133 list_del(&loop_device->node);
137 /* handle the devices on the "default" list next */
138 list_for_each_entry_safe(loop_device, tmp_device, &device_default_list, node) {
139 trigger_uevent(loop_device->name);
140 list_del(&loop_device->node);
144 /* handle devices on the "last" list, if any */
145 list_for_each_entry_safe(loop_device, tmp_device, &device_last_list, node) {
146 trigger_uevent(loop_device->name);
147 list_del(&loop_device->node);
152 static int is_device(const char *path)
154 char filename[PATH_SIZE];
157 /* look for the uevent file of the kobject */
158 strlcpy(filename, path, sizeof(filename));
159 strlcat(filename, "/uevent", sizeof(filename));
160 if (stat(filename, &statbuf) < 0)
163 if (!(statbuf.st_mode & S_IWUSR))
169 static void udev_scan_bus(void)
171 char base[PATH_SIZE];
175 strlcpy(base, sysfs_path, sizeof(base));
176 strlcat(base, "/bus", sizeof(base));
180 for (dent = readdir(dir); dent != NULL; dent = readdir(dir)) {
181 char dirname[PATH_SIZE];
183 struct dirent *dent2;
185 if (dent->d_name[0] == '.')
188 strlcpy(dirname, base, sizeof(dirname));
189 strlcat(dirname, "/", sizeof(dirname));
190 strlcat(dirname, dent->d_name, sizeof(dirname));
191 strlcat(dirname, "/devices", sizeof(dirname));
193 /* look for devices */
194 dir2 = opendir(dirname);
196 for (dent2 = readdir(dir2); dent2 != NULL; dent2 = readdir(dir2)) {
197 char dirname2[PATH_SIZE];
199 if (dent2->d_name[0] == '.')
202 strlcpy(dirname2, dirname, sizeof(dirname2));
203 strlcat(dirname2, "/", sizeof(dirname2));
204 strlcat(dirname2, dent2->d_name, sizeof(dirname2));
206 if (is_device(dirname2))
207 device_list_insert(dirname2);
216 static void udev_scan_block(void)
218 char base[PATH_SIZE];
223 /* skip if "block" is already a "class" */
224 strlcpy(base, sysfs_path, sizeof(base));
225 strlcat(base, "/class/block", sizeof(base));
226 if (stat(base, &statbuf) == 0)
229 strlcpy(base, sysfs_path, sizeof(base));
230 strlcat(base, "/block", sizeof(base));
234 for (dent = readdir(dir); dent != NULL; dent = readdir(dir)) {
235 char dirname[PATH_SIZE];
237 struct dirent *dent2;
239 if (dent->d_name[0] == '.')
242 strlcpy(dirname, base, sizeof(dirname));
243 strlcat(dirname, "/", sizeof(dirname));
244 strlcat(dirname, dent->d_name, sizeof(dirname));
245 if (is_device(dirname))
246 device_list_insert(dirname);
250 /* look for partitions */
251 dir2 = opendir(dirname);
253 for (dent2 = readdir(dir2); dent2 != NULL; dent2 = readdir(dir2)) {
254 char dirname2[PATH_SIZE];
256 if (dent2->d_name[0] == '.')
259 if (!strcmp(dent2->d_name,"device"))
262 strlcpy(dirname2, dirname, sizeof(dirname2));
263 strlcat(dirname2, "/", sizeof(dirname2));
264 strlcat(dirname2, dent2->d_name, sizeof(dirname2));
265 if (is_device(dirname2))
266 device_list_insert(dirname2);
275 static void udev_scan_class(void)
277 char base[PATH_SIZE];
281 strlcpy(base, sysfs_path, sizeof(base));
282 strlcat(base, "/class", sizeof(base));
286 for (dent = readdir(dir); dent != NULL; dent = readdir(dir)) {
287 char dirname[PATH_SIZE];
289 struct dirent *dent2;
291 if (dent->d_name[0] == '.')
294 strlcpy(dirname, base, sizeof(dirname));
295 strlcat(dirname, "/", sizeof(dirname));
296 strlcat(dirname, dent->d_name, sizeof(dirname));
297 dir2 = opendir(dirname);
299 for (dent2 = readdir(dir2); dent2 != NULL; dent2 = readdir(dir2)) {
300 char dirname2[PATH_SIZE];
302 if (dent2->d_name[0] == '.')
305 if (!strcmp(dent2->d_name, "device"))
308 strlcpy(dirname2, dirname, sizeof(dirname2));
309 strlcat(dirname2, "/", sizeof(dirname2));
310 strlcat(dirname2, dent2->d_name, sizeof(dirname2));
311 if (is_device(dirname2))
312 device_list_insert(dirname2);
321 int main(int argc, char *argv[], char *envp[])
325 logging_init("udevtrigger");
327 dbg("version %s", UDEV_VERSION);
329 udev_log_str = getenv("UDEV_LOG");
331 for (i = 1 ; i < argc; i++) {
334 if (strcmp(arg, "--verbose") == 0 || strcmp(arg, "-v") == 0)
336 else if (strcmp(arg, "--dry-run") == 0 || strcmp(arg, "-n") == 0)
339 fprintf(stderr, "Usage: udevtrigger [--verbose] [--dry-run]\n");