]> git.ipfire.org Git - thirdparty/systemd.git/blame - udevstart.c
fix usb_id and let scsi_id ignore "illegal request"
[thirdparty/systemd.git] / udevstart.c
CommitLineData
82b9a637
GKH
1/*
2 * udevstart.c
3 *
4 * Copyright (C) 2004 Greg Kroah-Hartman <greg@kroah.com>
5 *
6 * Quick and dirty way to populate a /dev with udev if your system
7 * does not have access to a shell. Based originally on a patch to udev
8 * from Harald Hoyer <harald@redhat.com>
9 *
10 * This program is free software; you can redistribute it and/or modify it
11 * under the terms of the GNU General Public License as published by the
12 * Free Software Foundation version 2 of the License.
13 *
14 * This program is distributed in the hope that it will be useful, but
15 * WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
17 * General Public License for more details.
18 *
19 * You should have received a copy of the GNU General Public License along
20 * with this program; if not, write to the Free Software Foundation, Inc.,
21 * 675 Mass Ave, Cambridge, MA 02139, USA.
22 *
23 */
24
25#include <stdlib.h>
0e306d08 26#include <stddef.h>
82b9a637
GKH
27#include <string.h>
28#include <stdio.h>
56a8a624 29#include <unistd.h>
82b9a637
GKH
30#include <errno.h>
31#include <ctype.h>
82b9a637 32#include <dirent.h>
56a8a624 33#include <signal.h>
82b9a637 34#include <sys/wait.h>
f22e9686 35#include <sys/stat.h>
f27125f9 36#include <sys/types.h>
82b9a637 37
7a947ce5 38#include "libsysfs/sysfs/libsysfs.h"
63f61c5c 39#include "udev_libc_wrapper.h"
c07669bd 40#include "udev_sysfs.h"
63f61c5c 41#include "udev.h"
6b493a20 42#include "udev_version.h"
82b9a637 43#include "logging.h"
e5e322bc 44#include "udev_rules.h"
9af5bb2f 45#include "udev_utils.h"
0e306d08 46#include "list.h"
82b9a637 47
b8476286
KS
48static const char *udev_run_str;
49static const char *udev_log_str;
8bd41f36 50static struct udev_rules rules;
b8476286 51
56a8a624 52#ifdef USE_LOG
6b493a20 53void log_message(int priority, const char *format, ...)
56a8a624 54{
6b493a20
KS
55 va_list args;
56
57 if (priority > udev_log_priority)
58 return;
59
60 va_start(args, format);
61 vsyslog(priority, format, args);
62 va_end(args);
56a8a624
KS
63}
64#endif
82b9a637 65
0e306d08 66struct device {
47241986 67 struct list_head node;
63f61c5c
KS
68 char path[PATH_SIZE];
69 char subsys[NAME_SIZE];
0e306d08
GKH
70};
71
72/* sort files in lexical order */
f22e9686 73static int device_list_insert(const char *path, char *subsystem, struct list_head *device_list)
0e306d08
GKH
74{
75 struct device *loop_device;
76 struct device *new_device;
77
f22e9686
KS
78 dbg("insert: '%s'\n", path);
79
47241986 80 list_for_each_entry(loop_device, device_list, node) {
0e306d08
GKH
81 if (strcmp(loop_device->path, path) > 0) {
82 break;
83 }
84 }
85
86 new_device = malloc(sizeof(struct device));
87 if (new_device == NULL) {
88 dbg("error malloc");
89 return -ENOMEM;
90 }
91
63f61c5c
KS
92 strlcpy(new_device->path, path, sizeof(new_device->path));
93 strlcpy(new_device->subsys, subsystem, sizeof(new_device->subsys));
47241986 94 list_add_tail(&new_device->node, &loop_device->node);
aee380b6 95 dbg("add '%s' from subsys '%s'", new_device->path, new_device->subsys);
0e306d08
GKH
96 return 0;
97}
98
0e306d08
GKH
99/* list of devices that we should run last due to any one of a number of reasons */
100static char *last_list[] = {
101 "/block/dm", /* on here because dm wants to have the block devices around before it */
102 NULL,
103};
104
70f630f6
GKH
105/* list of devices that we should run first due to any one of a number of reasons */
106static char *first_list[] = {
107 "/class/mem", /* people tend to like their memory devices around first... */
108 NULL,
109};
110
f22e9686 111static int add_device(const char *path, const char *subsystem)
f608f8ac 112{
7a947ce5 113 struct udevice udev;
7a947ce5 114 struct sysfs_class_device *class_dev;
f22e9686
KS
115 const char *devpath;
116
117 devpath = &path[strlen(sysfs_path)];
b8476286
KS
118
119 /* clear and set environment for next event */
120 clearenv();
121 setenv("ACTION", "add", 1);
7a947ce5 122 setenv("DEVPATH", devpath, 1);
af4b05d4 123 setenv("SUBSYSTEM", subsystem, 1);
b8476286
KS
124 setenv("UDEV_START", "1", 1);
125 if (udev_log_str)
126 setenv("UDEV_LOG", udev_log_str, 1);
127 if (udev_run_str)
128 setenv("UDEV_RUN", udev_run_str, 1);
56a8a624 129 dbg("exec: '%s' (%s)\n", devpath, path);
f22e9686 130
7a947ce5
KS
131 class_dev = sysfs_open_class_device_path(path);
132 if (class_dev == NULL) {
561d4c5a 133 dbg("sysfs_open_class_device_path failed");
c07669bd 134 return -1;
7a947ce5
KS
135 }
136
fb39f056 137 udev_init_device(&udev, devpath, subsystem, "add");
c07669bd 138 udev.devt = get_devt(class_dev);
66f74a2d 139 if (!udev.devt && udev.type != DEV_NET) {
561d4c5a 140 dbg("sysfs_open_class_device_path failed");
c07669bd
KS
141 return -1;
142 }
8bd41f36 143 udev_rules_get_name(&rules, &udev, class_dev);
c07669bd 144 if (udev.ignore_device) {
561d4c5a 145 dbg("device event will be ignored");
c07669bd
KS
146 goto exit;
147 }
148 if (udev.name[0] == '\0') {
561d4c5a 149 dbg("device node creation supressed");
c07669bd
KS
150 goto run;
151 }
7a947ce5 152
c07669bd 153 udev_add_device(&udev, class_dev);
81af4e05
KS
154 if (udev.devname[0] != '\0')
155 setenv("DEVNAME", udev.devname, 1);
c07669bd 156run:
821d0ec8
KS
157 if (udev_run && !list_empty(&udev.run_list)) {
158 struct name_entry *name_loop;
159
160 dbg("executing run list");
161 list_for_each_entry(name_loop, &udev.run_list, node)
be4bedd1 162 execute_program(name_loop->name, udev.subsystem, NULL, 0, NULL);
821d0ec8 163 }
c07669bd 164exit:
5d24c6ca 165 sysfs_close_class_device(class_dev);
56a8a624 166 udev_cleanup_device(&udev);
5d24c6ca
KS
167
168 return 0;
f608f8ac
KS
169}
170
0e306d08
GKH
171static void exec_list(struct list_head *device_list)
172{
173 struct device *loop_device;
174 struct device *tmp_device;
70f630f6
GKH
175 int i;
176
177 /* handle the "first" type devices first */
47241986 178 list_for_each_entry_safe(loop_device, tmp_device, device_list, node) {
f22e9686 179 for (i = 0; first_list[i] != NULL; i++) {
70f630f6 180 if (strncmp(loop_device->path, first_list[i], strlen(first_list[i])) == 0) {
7a947ce5 181 add_device(loop_device->path, loop_device->subsys);
47241986 182 list_del(&loop_device->node);
70f630f6
GKH
183 free(loop_device);
184 break;
185 }
186 }
187 }
0e306d08
GKH
188
189 /* handle the devices we are allowed to, excluding the "last" type devices */
47241986 190 list_for_each_entry_safe(loop_device, tmp_device, device_list, node) {
0e306d08 191 int found = 0;
f22e9686 192 for (i = 0; last_list[i] != NULL; i++) {
0e306d08
GKH
193 if (strncmp(loop_device->path, last_list[i], strlen(last_list[i])) == 0) {
194 found = 1;
195 break;
196 }
197 }
198 if (found)
199 continue;
200
7a947ce5 201 add_device(loop_device->path, loop_device->subsys);
47241986 202 list_del(&loop_device->node);
0e306d08
GKH
203 free(loop_device);
204 }
205
206 /* handle the rest of the devices left over, if any */
47241986 207 list_for_each_entry_safe(loop_device, tmp_device, device_list, node) {
7a947ce5 208 add_device(loop_device->path, loop_device->subsys);
47241986 209 list_del(&loop_device->node);
0e306d08
GKH
210 free(loop_device);
211 }
212}
213
f22e9686
KS
214static int has_devt(const char *directory)
215{
63f61c5c 216 char filename[PATH_SIZE];
f22e9686
KS
217 struct stat statbuf;
218
63f61c5c
KS
219 snprintf(filename, sizeof(filename), "%s/dev", directory);
220 filename[sizeof(filename)-1] = '\0';
f22e9686
KS
221
222 if (stat(filename, &statbuf) == 0)
223 return 1;
224
225 return 0;
226}
227
0e306d08 228static void udev_scan_block(void)
82b9a637 229{
63f61c5c 230 char base[PATH_SIZE];
e4dc0e11
KS
231 DIR *dir;
232 struct dirent *dent;
0e306d08 233 LIST_HEAD(device_list);
82b9a637 234
63f61c5c
KS
235 snprintf(base, sizeof(base), "%s/block", sysfs_path);
236 base[sizeof(base)-1] = '\0';
f22e9686
KS
237
238 dir = opendir(base);
e4dc0e11
KS
239 if (dir != NULL) {
240 for (dent = readdir(dir); dent != NULL; dent = readdir(dir)) {
63f61c5c 241 char dirname[PATH_SIZE];
e4dc0e11
KS
242 DIR *dir2;
243 struct dirent *dent2;
244
f22e9686 245 if (dent->d_name[0] == '.')
82b9a637
GKH
246 continue;
247
63f61c5c
KS
248 snprintf(dirname, sizeof(dirname), "%s/%s", base, dent->d_name);
249 dirname[sizeof(dirname)-1] = '\0';
f22e9686
KS
250 if (has_devt(dirname))
251 device_list_insert(dirname, "block", &device_list);
252 else
253 continue;
0e306d08 254
56a8a624 255 /* look for partitions */
82b9a637 256 dir2 = opendir(dirname);
e4dc0e11
KS
257 if (dir2 != NULL) {
258 for (dent2 = readdir(dir2); dent2 != NULL; dent2 = readdir(dir2)) {
63f61c5c 259 char dirname2[PATH_SIZE];
82b9a637 260
f22e9686 261 if (dent2->d_name[0] == '.')
82b9a637
GKH
262 continue;
263
63f61c5c
KS
264 snprintf(dirname2, sizeof(dirname2), "%s/%s", dirname, dent2->d_name);
265 dirname2[sizeof(dirname2)-1] = '\0';
f22e9686
KS
266
267 if (has_devt(dirname2))
268 device_list_insert(dirname2, "block", &device_list);
82b9a637 269 }
e13fa599 270 closedir(dir2);
82b9a637
GKH
271 }
272 }
e13fa599 273 closedir(dir);
82b9a637 274 }
0e306d08
GKH
275 exec_list(&device_list);
276}
277
278static void udev_scan_class(void)
279{
63f61c5c 280 char base[PATH_SIZE];
0e306d08
GKH
281 DIR *dir;
282 struct dirent *dent;
283 LIST_HEAD(device_list);
284
63f61c5c
KS
285 snprintf(base, sizeof(base), "%s/class", sysfs_path);
286 base[sizeof(base)-1] = '\0';
f22e9686
KS
287
288 dir = opendir(base);
e4dc0e11
KS
289 if (dir != NULL) {
290 for (dent = readdir(dir); dent != NULL; dent = readdir(dir)) {
63f61c5c 291 char dirname[PATH_SIZE];
e4dc0e11
KS
292 DIR *dir2;
293 struct dirent *dent2;
294
f22e9686 295 if (dent->d_name[0] == '.')
82b9a637
GKH
296 continue;
297
63f61c5c
KS
298 snprintf(dirname, sizeof(dirname), "%s/%s", base, dent->d_name);
299 dirname[sizeof(dirname)-1] = '\0';
56a8a624 300
82b9a637 301 dir2 = opendir(dirname);
e4dc0e11
KS
302 if (dir2 != NULL) {
303 for (dent2 = readdir(dir2); dent2 != NULL; dent2 = readdir(dir2)) {
63f61c5c 304 char dirname2[PATH_SIZE];
82b9a637 305
f22e9686 306 if (dent2->d_name[0] == '.')
82b9a637
GKH
307 continue;
308
63f61c5c
KS
309 snprintf(dirname2, sizeof(dirname2), "%s/%s", dirname, dent2->d_name);
310 dirname2[sizeof(dirname2)-1] = '\0';
f22e9686 311
aee380b6 312 /* pass the net class as it is */
f22e9686 313 if (strcmp(dent->d_name, "net") == 0)
aee380b6 314 device_list_insert(dirname2, "net", &device_list);
f22e9686
KS
315 else if (has_devt(dirname2))
316 device_list_insert(dirname2, dent->d_name, &device_list);
82b9a637 317 }
e13fa599 318 closedir(dir2);
82b9a637
GKH
319 }
320 }
e13fa599 321 closedir(dir);
82b9a637 322 }
0e306d08 323 exec_list(&device_list);
82b9a637
GKH
324}
325
56a8a624 326static void asmlinkage sig_handler(int signum)
82b9a637 327{
56a8a624
KS
328 switch (signum) {
329 case SIGALRM:
330 exit(1);
331 case SIGINT:
332 case SIGTERM:
333 exit(20 + signum);
334 }
335}
336
337int main(int argc, char *argv[], char *envp[])
338{
339 struct sigaction act;
340
66f74a2d 341 logging_init("udevstart");
56a8a624 342 udev_init_config();
b8476286
KS
343 dbg("version %s", UDEV_VERSION);
344
345 udev_run_str = getenv("UDEV_RUN");
346 udev_log_str = getenv("UDEV_LOG");
347
6b493a20 348 /* disable all logging if not explicitely requested */
b8476286 349 if (udev_log_str == NULL)
6b493a20 350 udev_log_priority = 0;
56a8a624
KS
351
352 /* set signal handlers */
353 memset(&act, 0x00, sizeof(act));
354 act.sa_handler = (void (*) (int))sig_handler;
355 sigemptyset (&act.sa_mask);
356 act.sa_flags = 0;
357 sigaction(SIGALRM, &act, NULL);
358 sigaction(SIGINT, &act, NULL);
359 sigaction(SIGTERM, &act, NULL);
360
361 /* trigger timeout to prevent hanging processes */
8815afa1 362 alarm(UDEV_ALARM_TIMEOUT);
56a8a624 363
8bd41f36 364 udev_rules_init(&rules, 1);
56a8a624 365
0e306d08 366 udev_scan_block();
56a8a624 367 udev_scan_class();
af4b05d4 368
8bd41f36 369 udev_rules_close(&rules);
6b493a20 370 logging_close();
3f20eac0 371 return 0;
82b9a637 372}