chiark / gitweb /
add more warnings for invalid key operations
[elogind.git] / udevtrigger.c
1 /*
2  * udevtrigger.c
3  *
4  * Copyright (C) 2004-2006 Kay Sievers <kay@vrfy.org>
5  * Copyright (C) 2006 Hannes Reinecke <hare@suse.de>
6  *
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.
10  * 
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.
15  * 
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.
19  *
20  */
21
22 #include <stdlib.h>
23 #include <stddef.h>
24 #include <string.h>
25 #include <stdio.h>
26 #include <unistd.h>
27 #include <errno.h>
28 #include <dirent.h>
29 #include <fcntl.h>
30 #include <syslog.h>
31 #include <sys/stat.h>
32 #include <sys/types.h>
33
34 #include "udev.h"
35
36 static const char *udev_log_str;
37 static int verbose;
38 static int dry_run;
39
40 #ifdef USE_LOG
41 void log_message(int priority, const char *format, ...)
42 {
43         va_list args;
44
45         if (priority > udev_log_priority)
46                 return;
47
48         va_start(args, format);
49         vsyslog(priority, format, args);
50         va_end(args);
51 }
52 #endif
53
54 /* list of devices that we should run last due to any one of a number of reasons */
55 static char *last_list[] = {
56         "/class/block/md",
57         "/class/block/dm-",
58         "/block/md",
59         "/block/dm-",
60         NULL
61 };
62
63 /* list of devices that we should run first due to any one of a number of reasons */
64 static char *first_list[] = {
65         "/class/mem",
66         "/class/tty",
67         NULL
68 };
69
70 LIST_HEAD(device_first_list);
71 LIST_HEAD(device_default_list);
72 LIST_HEAD(device_last_list);
73
74 static int device_list_insert(const char *path)
75 {
76         struct list_head *device_list = &device_default_list;
77         const char *devpath = &path[strlen(sysfs_path)];
78         int i;
79
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;
83                         break;
84                 }
85         }
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;
89                         break;
90                 }
91         }
92
93         dbg("add '%s'" , path);
94         /* double entries will be ignored */
95         name_list_add(device_list, path, 0);
96         return 0;
97 }
98
99 static void trigger_uevent(const char *path)
100 {
101         char filename[PATH_SIZE];
102         int fd;
103
104         strlcpy(filename, path, sizeof(filename));
105         strlcat(filename, "/uevent", sizeof(filename));
106
107         if (verbose)
108                 printf("%s\n", path);
109
110         if (dry_run)
111                 return;
112
113         fd = open(filename, O_WRONLY);
114         if (fd < 0) {
115                 dbg("error on opening %s: %s\n", filename, strerror(errno));
116                 return;
117         }
118
119         if (write(fd, "add", 3) < 0)
120                 info("error on triggering %s: %s\n", filename, strerror(errno));
121
122         close(fd);
123 }
124
125 static void exec_lists(void)
126 {
127         struct name_entry *loop_device;
128         struct name_entry *tmp_device;
129
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);
134                 free(loop_device);
135         }
136
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);
141                 free(loop_device);
142         }
143
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);
148                 free(loop_device);
149         }
150 }
151
152 static int is_device(const char *path)
153 {
154         char filename[PATH_SIZE];
155         struct stat statbuf;
156
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)
161                 return 0;
162
163         if (!(statbuf.st_mode & S_IWUSR))
164                 return 0;
165
166         return 1;
167 }
168
169 static void udev_scan_bus(void)
170 {
171         char base[PATH_SIZE];
172         DIR *dir;
173         struct dirent *dent;
174
175         strlcpy(base, sysfs_path, sizeof(base));
176         strlcat(base, "/bus", sizeof(base));
177
178         dir = opendir(base);
179         if (dir != NULL) {
180                 for (dent = readdir(dir); dent != NULL; dent = readdir(dir)) {
181                         char dirname[PATH_SIZE];
182                         DIR *dir2;
183                         struct dirent *dent2;
184
185                         if (dent->d_name[0] == '.')
186                                 continue;
187
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));
192
193                         /* look for devices */
194                         dir2 = opendir(dirname);
195                         if (dir2 != NULL) {
196                                 for (dent2 = readdir(dir2); dent2 != NULL; dent2 = readdir(dir2)) {
197                                         char dirname2[PATH_SIZE];
198
199                                         if (dent2->d_name[0] == '.')
200                                                 continue;
201
202                                         strlcpy(dirname2, dirname, sizeof(dirname2));
203                                         strlcat(dirname2, "/", sizeof(dirname2));
204                                         strlcat(dirname2, dent2->d_name, sizeof(dirname2));
205
206                                         if (is_device(dirname2))
207                                                 device_list_insert(dirname2);
208                                 }
209                                 closedir(dir2);
210                         }
211                 }
212                 closedir(dir);
213         }
214 }
215
216 static void udev_scan_block(void)
217 {
218         char base[PATH_SIZE];
219         DIR *dir;
220         struct dirent *dent;
221         struct stat statbuf;
222
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)
227                 return;
228
229         strlcpy(base, sysfs_path, sizeof(base));
230         strlcat(base, "/block", sizeof(base));
231
232         dir = opendir(base);
233         if (dir != NULL) {
234                 for (dent = readdir(dir); dent != NULL; dent = readdir(dir)) {
235                         char dirname[PATH_SIZE];
236                         DIR *dir2;
237                         struct dirent *dent2;
238
239                         if (dent->d_name[0] == '.')
240                                 continue;
241
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);
247                         else
248                                 continue;
249
250                         /* look for partitions */
251                         dir2 = opendir(dirname);
252                         if (dir2 != NULL) {
253                                 for (dent2 = readdir(dir2); dent2 != NULL; dent2 = readdir(dir2)) {
254                                         char dirname2[PATH_SIZE];
255
256                                         if (dent2->d_name[0] == '.')
257                                                 continue;
258
259                                         if (!strcmp(dent2->d_name,"device"))
260                                                 continue;
261
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);
267                                 }
268                                 closedir(dir2);
269                         }
270                 }
271                 closedir(dir);
272         }
273 }
274
275 static void udev_scan_class(void)
276 {
277         char base[PATH_SIZE];
278         DIR *dir;
279         struct dirent *dent;
280
281         strlcpy(base, sysfs_path, sizeof(base));
282         strlcat(base, "/class", sizeof(base));
283
284         dir = opendir(base);
285         if (dir != NULL) {
286                 for (dent = readdir(dir); dent != NULL; dent = readdir(dir)) {
287                         char dirname[PATH_SIZE];
288                         DIR *dir2;
289                         struct dirent *dent2;
290
291                         if (dent->d_name[0] == '.')
292                                 continue;
293
294                         strlcpy(dirname, base, sizeof(dirname));
295                         strlcat(dirname, "/", sizeof(dirname));
296                         strlcat(dirname, dent->d_name, sizeof(dirname));
297                         dir2 = opendir(dirname);
298                         if (dir2 != NULL) {
299                                 for (dent2 = readdir(dir2); dent2 != NULL; dent2 = readdir(dir2)) {
300                                         char dirname2[PATH_SIZE];
301
302                                         if (dent2->d_name[0] == '.')
303                                                 continue;
304
305                                         if (!strcmp(dent2->d_name, "device"))
306                                                 continue;
307
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);
313                                 }
314                                 closedir(dir2);
315                         }
316                 }
317                 closedir(dir);
318         }
319 }
320
321 int main(int argc, char *argv[], char *envp[])
322 {
323         int i;
324
325         logging_init("udevtrigger");
326         udev_config_init();
327         dbg("version %s", UDEV_VERSION);
328
329         udev_log_str = getenv("UDEV_LOG");
330
331         for (i = 1 ; i < argc; i++) {
332                 char *arg = argv[i];
333
334                 if (strcmp(arg, "--verbose") == 0 || strcmp(arg, "-v") == 0)
335                         verbose = 1;
336                 else if (strcmp(arg, "--dry-run") == 0 || strcmp(arg, "-n") == 0)
337                         dry_run = 1;
338                 else {
339                         fprintf(stderr, "Usage: udevtrigger [--verbose] [--dry-run]\n");
340                         goto exit;
341                 }
342         }
343
344         sysfs_init();
345
346         udev_scan_bus();
347         udev_scan_class();
348         udev_scan_block();
349         exec_lists();
350
351         sysfs_cleanup();
352 exit:
353         logging_close();
354         return 0;
355 }