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;
79 for (i = 0; first_list[i] != NULL; i++) {
80 if (strncmp(path, first_list[i], strlen(first_list[i])) == 0) {
81 device_list = &device_first_list;
85 for (i = 0; last_list[i] != NULL; i++) {
86 if (strncmp(path, last_list[i], strlen(last_list[i])) == 0) {
87 device_list = &device_last_list;
92 dbg("add '%s'" , path);
93 /* double entries will be ignored */
94 name_list_add(device_list, path, 0);
98 static void trigger_uevent(const char *path)
100 char filename[PATH_SIZE];
103 strlcpy(filename, path, sizeof(filename));
104 strlcat(filename, "/uevent", sizeof(filename));
107 printf("%s\n", path);
112 fd = open(filename, O_WRONLY);
114 dbg("error on opening %s: %s\n", filename, strerror(errno));
118 if (write(fd, "add", 3) < 0)
119 info("error on triggering %s: %s\n", filename, strerror(errno));
124 static void exec_lists(void)
126 struct name_entry *loop_device;
127 struct name_entry *tmp_device;
129 /* handle the devices on the "first" list first */
130 list_for_each_entry_safe(loop_device, tmp_device, &device_first_list, node) {
131 trigger_uevent(loop_device->name);
132 list_del(&loop_device->node);
136 /* handle the devices on the "default" list next */
137 list_for_each_entry_safe(loop_device, tmp_device, &device_default_list, node) {
138 trigger_uevent(loop_device->name);
139 list_del(&loop_device->node);
143 /* handle devices on the "last" list, if any */
144 list_for_each_entry_safe(loop_device, tmp_device, &device_last_list, node) {
145 trigger_uevent(loop_device->name);
146 list_del(&loop_device->node);
151 static int is_device(const char *path)
153 char filename[PATH_SIZE];
156 /* look for the uevent file of the kobject */
157 strlcpy(filename, path, sizeof(filename));
158 strlcat(filename, "/uevent", sizeof(filename));
159 if (stat(filename, &statbuf) < 0)
162 if (!(statbuf.st_mode & S_IWUSR))
168 static void udev_scan_bus(void)
170 char base[PATH_SIZE];
174 strlcpy(base, sysfs_path, sizeof(base));
175 strlcat(base, "/bus", sizeof(base));
179 for (dent = readdir(dir); dent != NULL; dent = readdir(dir)) {
180 char dirname[PATH_SIZE];
182 struct dirent *dent2;
184 if (dent->d_name[0] == '.')
187 strlcpy(dirname, base, sizeof(dirname));
188 strlcat(dirname, "/", sizeof(dirname));
189 strlcat(dirname, dent->d_name, sizeof(dirname));
190 strlcat(dirname, "/devices", sizeof(dirname));
192 /* look for devices */
193 dir2 = opendir(dirname);
195 for (dent2 = readdir(dir2); dent2 != NULL; dent2 = readdir(dir2)) {
196 char dirname2[PATH_SIZE];
198 if (dent2->d_name[0] == '.')
201 strlcpy(dirname2, dirname, sizeof(dirname2));
202 strlcat(dirname2, "/", sizeof(dirname2));
203 strlcat(dirname2, dent2->d_name, sizeof(dirname2));
205 if (is_device(dirname2))
206 device_list_insert(dirname2);
215 static void udev_scan_block(void)
217 char base[PATH_SIZE];
222 /* skip if "block" is already a "class" */
223 strlcpy(base, sysfs_path, sizeof(base));
224 strlcat(base, "/class/block", sizeof(base));
225 if (stat(base, &statbuf) == 0)
228 strlcpy(base, sysfs_path, sizeof(base));
229 strlcat(base, "/block", sizeof(base));
233 for (dent = readdir(dir); dent != NULL; dent = readdir(dir)) {
234 char dirname[PATH_SIZE];
236 struct dirent *dent2;
238 if (dent->d_name[0] == '.')
241 strlcpy(dirname, base, sizeof(dirname));
242 strlcat(dirname, "/", sizeof(dirname));
243 strlcat(dirname, dent->d_name, sizeof(dirname));
244 if (is_device(dirname))
245 device_list_insert(dirname);
249 /* look for partitions */
250 dir2 = opendir(dirname);
252 for (dent2 = readdir(dir2); dent2 != NULL; dent2 = readdir(dir2)) {
253 char dirname2[PATH_SIZE];
255 if (dent2->d_name[0] == '.')
258 if (!strcmp(dent2->d_name,"device"))
261 strlcpy(dirname2, dirname, sizeof(dirname2));
262 strlcat(dirname2, "/", sizeof(dirname2));
263 strlcat(dirname2, dent2->d_name, sizeof(dirname2));
264 if (is_device(dirname2))
265 device_list_insert(dirname2);
274 static void udev_scan_class(void)
276 char base[PATH_SIZE];
280 strlcpy(base, sysfs_path, sizeof(base));
281 strlcat(base, "/class", sizeof(base));
285 for (dent = readdir(dir); dent != NULL; dent = readdir(dir)) {
286 char dirname[PATH_SIZE];
288 struct dirent *dent2;
290 if (dent->d_name[0] == '.')
293 strlcpy(dirname, base, sizeof(dirname));
294 strlcat(dirname, "/", sizeof(dirname));
295 strlcat(dirname, dent->d_name, sizeof(dirname));
296 dir2 = opendir(dirname);
298 for (dent2 = readdir(dir2); dent2 != NULL; dent2 = readdir(dir2)) {
299 char dirname2[PATH_SIZE];
301 if (dent2->d_name[0] == '.')
304 if (!strcmp(dent2->d_name, "device"))
307 strlcpy(dirname2, dirname, sizeof(dirname2));
308 strlcat(dirname2, "/", sizeof(dirname2));
309 strlcat(dirname2, dent2->d_name, sizeof(dirname2));
310 if (is_device(dirname2))
311 device_list_insert(dirname2);
320 int main(int argc, char *argv[], char *envp[])
324 logging_init("udevtrigger");
326 dbg("version %s", UDEV_VERSION);
328 udev_log_str = getenv("UDEV_LOG");
330 for (i = 1 ; i < argc; i++) {
333 if (strcmp(arg, "--verbose") == 0 || strcmp(arg, "-v") == 0)
335 else if (strcmp(arg, "--dry-run") == 0 || strcmp(arg, "-n") == 0)
338 fprintf(stderr, "Usage: udevtrigger [--verbose] [--dry-run]\n");