2 * Copyright (C) 2004-2006 Kay Sievers <kay@vrfy.org>
3 * Copyright (C) 2006 Hannes Reinecke <hare@suse.de>
5 * This program is free software; you can redistribute it and/or modify it
6 * under the terms of the GNU General Public License as published by the
7 * Free Software Foundation version 2 of the License.
9 * This program is distributed in the hope that it will be useful, but
10 * WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 * General Public License for more details.
14 * You should have received a copy of the GNU General Public License along
15 * with this program; if not, write to the Free Software Foundation, Inc.,
16 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
30 #include <sys/types.h>
39 void log_message(int priority, const char *format, ...)
43 if (priority > udev_log_priority)
46 va_start(args, format);
47 vsyslog(priority, format, args);
52 /* list of devices that we should run last due to any one of a number of reasons */
53 static char *last_list[] = {
61 /* list of devices that we should run first due to any one of a number of reasons */
62 static char *first_list[] = {
68 LIST_HEAD(device_first_list);
69 LIST_HEAD(device_default_list);
70 LIST_HEAD(device_last_list);
72 static int device_list_insert(const char *path)
74 struct list_head *device_list = &device_default_list;
75 const char *devpath = &path[strlen(sysfs_path)];
78 for (i = 0; first_list[i] != NULL; i++) {
79 if (strncmp(devpath, first_list[i], strlen(first_list[i])) == 0) {
80 device_list = &device_first_list;
84 for (i = 0; last_list[i] != NULL; i++) {
85 if (strncmp(devpath, last_list[i], strlen(last_list[i])) == 0) {
86 device_list = &device_last_list;
91 dbg("add '%s'" , path);
92 /* double entries will be ignored */
93 name_list_add(device_list, path, 0);
97 static void trigger_uevent(const char *path)
99 char filename[PATH_SIZE];
102 strlcpy(filename, path, sizeof(filename));
103 strlcat(filename, "/uevent", sizeof(filename));
106 printf("%s\n", path);
111 fd = open(filename, O_WRONLY);
113 dbg("error on opening %s: %s\n", filename, strerror(errno));
117 if (write(fd, "add", 3) < 0)
118 info("error on triggering %s: %s\n", filename, strerror(errno));
123 static void exec_lists(void)
125 struct name_entry *loop_device;
126 struct name_entry *tmp_device;
128 /* handle the devices on the "first" list first */
129 list_for_each_entry_safe(loop_device, tmp_device, &device_first_list, node) {
130 trigger_uevent(loop_device->name);
131 list_del(&loop_device->node);
135 /* handle the devices on the "default" list next */
136 list_for_each_entry_safe(loop_device, tmp_device, &device_default_list, node) {
137 trigger_uevent(loop_device->name);
138 list_del(&loop_device->node);
142 /* handle devices on the "last" list, if any */
143 list_for_each_entry_safe(loop_device, tmp_device, &device_last_list, node) {
144 trigger_uevent(loop_device->name);
145 list_del(&loop_device->node);
150 static int is_device(const char *path)
152 char filename[PATH_SIZE];
155 /* look for the uevent file of the kobject */
156 strlcpy(filename, path, sizeof(filename));
157 strlcat(filename, "/uevent", sizeof(filename));
158 if (stat(filename, &statbuf) < 0)
161 if (!(statbuf.st_mode & S_IWUSR))
167 static void scan_bus(void)
169 char base[PATH_SIZE];
173 strlcpy(base, sysfs_path, sizeof(base));
174 strlcat(base, "/bus", sizeof(base));
178 for (dent = readdir(dir); dent != NULL; dent = readdir(dir)) {
179 char dirname[PATH_SIZE];
181 struct dirent *dent2;
183 if (dent->d_name[0] == '.')
186 strlcpy(dirname, base, sizeof(dirname));
187 strlcat(dirname, "/", sizeof(dirname));
188 strlcat(dirname, dent->d_name, sizeof(dirname));
189 strlcat(dirname, "/devices", sizeof(dirname));
191 /* look for devices */
192 dir2 = opendir(dirname);
194 for (dent2 = readdir(dir2); dent2 != NULL; dent2 = readdir(dir2)) {
195 char dirname2[PATH_SIZE];
197 if (dent2->d_name[0] == '.')
200 strlcpy(dirname2, dirname, sizeof(dirname2));
201 strlcat(dirname2, "/", sizeof(dirname2));
202 strlcat(dirname2, dent2->d_name, sizeof(dirname2));
204 if (is_device(dirname2))
205 device_list_insert(dirname2);
214 static void scan_block(void)
216 char base[PATH_SIZE];
221 /* skip if "block" is already a "class" */
222 strlcpy(base, sysfs_path, sizeof(base));
223 strlcat(base, "/class/block", sizeof(base));
224 if (stat(base, &statbuf) == 0)
227 strlcpy(base, sysfs_path, sizeof(base));
228 strlcat(base, "/block", sizeof(base));
232 for (dent = readdir(dir); dent != NULL; dent = readdir(dir)) {
233 char dirname[PATH_SIZE];
235 struct dirent *dent2;
237 if (dent->d_name[0] == '.')
240 strlcpy(dirname, base, sizeof(dirname));
241 strlcat(dirname, "/", sizeof(dirname));
242 strlcat(dirname, dent->d_name, sizeof(dirname));
243 if (is_device(dirname))
244 device_list_insert(dirname);
248 /* look for partitions */
249 dir2 = opendir(dirname);
251 for (dent2 = readdir(dir2); dent2 != NULL; dent2 = readdir(dir2)) {
252 char dirname2[PATH_SIZE];
254 if (dent2->d_name[0] == '.')
257 if (!strcmp(dent2->d_name,"device"))
260 strlcpy(dirname2, dirname, sizeof(dirname2));
261 strlcat(dirname2, "/", sizeof(dirname2));
262 strlcat(dirname2, dent2->d_name, sizeof(dirname2));
263 if (is_device(dirname2))
264 device_list_insert(dirname2);
273 static void scan_class(void)
275 char base[PATH_SIZE];
279 strlcpy(base, sysfs_path, sizeof(base));
280 strlcat(base, "/class", sizeof(base));
284 for (dent = readdir(dir); dent != NULL; dent = readdir(dir)) {
285 char dirname[PATH_SIZE];
287 struct dirent *dent2;
289 if (dent->d_name[0] == '.')
292 strlcpy(dirname, base, sizeof(dirname));
293 strlcat(dirname, "/", sizeof(dirname));
294 strlcat(dirname, dent->d_name, sizeof(dirname));
295 dir2 = opendir(dirname);
297 for (dent2 = readdir(dir2); dent2 != NULL; dent2 = readdir(dir2)) {
298 char dirname2[PATH_SIZE];
300 if (dent2->d_name[0] == '.')
303 if (!strcmp(dent2->d_name, "device"))
306 strlcpy(dirname2, dirname, sizeof(dirname2));
307 strlcat(dirname2, "/", sizeof(dirname2));
308 strlcat(dirname2, dent2->d_name, sizeof(dirname2));
309 if (is_device(dirname2))
310 device_list_insert(dirname2);
319 static void scan_failed(void)
321 char base[PATH_SIZE];
325 strlcpy(base, udev_root, sizeof(base));
326 strlcat(base, "/", sizeof(base));
327 strlcat(base, EVENT_FAILED_DIR, sizeof(base));
331 for (dent = readdir(dir); dent != NULL; dent = readdir(dir)) {
332 char linkname[PATH_SIZE];
333 char target[PATH_SIZE];
336 if (dent->d_name[0] == '.')
339 strlcpy(linkname, base, sizeof(linkname));
340 strlcat(linkname, "/", sizeof(linkname));
341 strlcat(linkname, dent->d_name, sizeof(linkname));
343 len = readlink(linkname, target, sizeof(target));
348 if (is_device(target))
349 device_list_insert(target);
357 int main(int argc, char *argv[], char *envp[])
362 logging_init("udevtrigger");
364 dbg("version %s", UDEV_VERSION);
367 for (i = 1 ; i < argc; i++) {
370 if (strcmp(arg, "--verbose") == 0 || strcmp(arg, "-v") == 0) {
372 } else if (strcmp(arg, "--dry-run") == 0 || strcmp(arg, "-n") == 0) {
374 } else if (strcmp(arg, "--retry-failed") == 0 || strcmp(arg, "-F") == 0) {
376 } else if (strcmp(arg, "--help") == 0 || strcmp(arg, "-h") == 0) {
377 printf("Usage: udevtrigger [--help] [--verbose] [--dry-run] [--retry-failed]\n");
380 fprintf(stderr, "unrecognized option '%s'\n", arg);
381 err("unrecognized option '%s'\n", arg);