]>
Commit | Line | Data |
---|---|---|
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> | |
29 | #include <errno.h> | |
30 | #include <ctype.h> | |
82b9a637 GKH |
31 | #include <dirent.h> |
32 | #include <sys/wait.h> | |
f27125f9 | 33 | #include <sys/types.h> |
34 | #include <unistd.h> | |
82b9a637 GKH |
35 | |
36 | #include "logging.h" | |
9b28a52a | 37 | #include "udev_lib.h" |
0e306d08 | 38 | #include "list.h" |
eb6c7cd0 | 39 | #include "udev.h" |
82b9a637 GKH |
40 | |
41 | ||
e4dc0e11 KS |
42 | #define MAX_PATHLEN 1024 |
43 | #define SYSBLOCK "/sys/block" | |
44 | #define SYSCLASS "/sys/class" | |
82b9a637 | 45 | |
0e306d08 GKH |
46 | struct device { |
47 | struct list_head list; | |
48 | char path[MAX_PATHLEN]; | |
49 | char subsys[MAX_PATHLEN]; | |
50 | }; | |
51 | ||
52 | /* sort files in lexical order */ | |
53 | static int device_list_insert(char *path, char *subsystem, struct list_head *device_list) | |
54 | { | |
55 | struct device *loop_device; | |
56 | struct device *new_device; | |
57 | ||
58 | list_for_each_entry(loop_device, device_list, list) { | |
59 | if (strcmp(loop_device->path, path) > 0) { | |
60 | break; | |
61 | } | |
62 | } | |
63 | ||
64 | new_device = malloc(sizeof(struct device)); | |
65 | if (new_device == NULL) { | |
66 | dbg("error malloc"); | |
67 | return -ENOMEM; | |
68 | } | |
69 | ||
70 | strfieldcpy(new_device->path, path); | |
71 | strfieldcpy(new_device->subsys, subsystem); | |
72 | list_add_tail(&new_device->list, &loop_device->list); | |
aee380b6 | 73 | dbg("add '%s' from subsys '%s'", new_device->path, new_device->subsys); |
0e306d08 GKH |
74 | return 0; |
75 | } | |
76 | ||
0e306d08 GKH |
77 | /* list of devices that we should run last due to any one of a number of reasons */ |
78 | static char *last_list[] = { | |
79 | "/block/dm", /* on here because dm wants to have the block devices around before it */ | |
80 | NULL, | |
81 | }; | |
82 | ||
70f630f6 GKH |
83 | /* list of devices that we should run first due to any one of a number of reasons */ |
84 | static char *first_list[] = { | |
85 | "/class/mem", /* people tend to like their memory devices around first... */ | |
86 | NULL, | |
87 | }; | |
88 | ||
f608f8ac KS |
89 | static void add_device(char *path, char *subsys, int fake) |
90 | { | |
91 | char *argv[3]; | |
92 | ||
93 | /* fake argument vector and environment for callouts and dev.d/ */ | |
94 | argv[0] = "udev"; | |
95 | argv[1] = subsys; | |
96 | argv[2] = NULL; | |
97 | ||
98 | main_argv = argv; | |
99 | setenv("DEVPATH", path, 1); | |
100 | setenv("ACTION", "add", 1); | |
101 | udev_add_device(path, subsys, fake); | |
102 | } | |
103 | ||
0e306d08 GKH |
104 | static void exec_list(struct list_head *device_list) |
105 | { | |
106 | struct device *loop_device; | |
107 | struct device *tmp_device; | |
70f630f6 GKH |
108 | int i; |
109 | ||
110 | /* handle the "first" type devices first */ | |
111 | list_for_each_entry_safe(loop_device, tmp_device, device_list, list) { | |
112 | for (i=0; first_list[i] != NULL; i++) { | |
113 | if (strncmp(loop_device->path, first_list[i], strlen(first_list[i])) == 0) { | |
f608f8ac | 114 | add_device(loop_device->path, loop_device->subsys, NOFAKE); |
70f630f6 GKH |
115 | list_del(&loop_device->list); |
116 | free(loop_device); | |
117 | break; | |
118 | } | |
119 | } | |
120 | } | |
0e306d08 GKH |
121 | |
122 | /* handle the devices we are allowed to, excluding the "last" type devices */ | |
123 | list_for_each_entry_safe(loop_device, tmp_device, device_list, list) { | |
124 | int found = 0; | |
0e306d08 GKH |
125 | for (i=0; last_list[i] != NULL; i++) { |
126 | if (strncmp(loop_device->path, last_list[i], strlen(last_list[i])) == 0) { | |
127 | found = 1; | |
128 | break; | |
129 | } | |
130 | } | |
131 | if (found) | |
132 | continue; | |
133 | ||
f608f8ac | 134 | add_device(loop_device->path, loop_device->subsys, NOFAKE); |
0e306d08 GKH |
135 | list_del(&loop_device->list); |
136 | free(loop_device); | |
137 | } | |
138 | ||
139 | /* handle the rest of the devices left over, if any */ | |
140 | list_for_each_entry_safe(loop_device, tmp_device, device_list, list) { | |
f608f8ac | 141 | add_device(loop_device->path, loop_device->subsys, NOFAKE); |
0e306d08 GKH |
142 | list_del(&loop_device->list); |
143 | free(loop_device); | |
144 | } | |
145 | } | |
146 | ||
147 | static void udev_scan_block(void) | |
82b9a637 | 148 | { |
e4dc0e11 KS |
149 | DIR *dir; |
150 | struct dirent *dent; | |
0e306d08 | 151 | LIST_HEAD(device_list); |
82b9a637 | 152 | |
0e306d08 | 153 | dir = opendir(SYSBLOCK); |
e4dc0e11 KS |
154 | if (dir != NULL) { |
155 | for (dent = readdir(dir); dent != NULL; dent = readdir(dir)) { | |
156 | char dirname[MAX_PATHLEN]; | |
157 | DIR *dir2; | |
158 | struct dirent *dent2; | |
159 | ||
160 | if ((strcmp(dent->d_name, ".") == 0) || | |
161 | (strcmp(dent->d_name, "..") == 0)) | |
82b9a637 GKH |
162 | continue; |
163 | ||
0e306d08 GKH |
164 | snprintf(dirname, MAX_PATHLEN, "/block/%s", dent->d_name); |
165 | dirname[MAX_PATHLEN-1] = '\0'; | |
166 | device_list_insert(dirname, "block", &device_list); | |
167 | ||
168 | snprintf(dirname, MAX_PATHLEN, "%s/%s", SYSBLOCK, dent->d_name); | |
82b9a637 | 169 | dir2 = opendir(dirname); |
e4dc0e11 KS |
170 | if (dir2 != NULL) { |
171 | for (dent2 = readdir(dir2); dent2 != NULL; dent2 = readdir(dir2)) { | |
0e306d08 | 172 | char dirname2[MAX_PATHLEN]; |
e4dc0e11 KS |
173 | DIR *dir3; |
174 | struct dirent *dent3; | |
82b9a637 GKH |
175 | |
176 | if ((strcmp(dent2->d_name, ".") == 0) || | |
177 | (strcmp(dent2->d_name, "..") == 0)) | |
178 | continue; | |
179 | ||
180 | snprintf(dirname2, MAX_PATHLEN, "%s/%s", dirname, dent2->d_name); | |
e4dc0e11 | 181 | dirname2[MAX_PATHLEN-1] = '\0'; |
82b9a637 GKH |
182 | |
183 | dir3 = opendir(dirname2); | |
e4dc0e11 KS |
184 | if (dir3 != NULL) { |
185 | for (dent3 = readdir(dir3); dent3 != NULL; dent3 = readdir(dir3)) { | |
82b9a637 GKH |
186 | char filename[MAX_PATHLEN]; |
187 | ||
188 | if (strcmp(dent3->d_name, "dev") == 0) { | |
0e306d08 | 189 | snprintf(filename, MAX_PATHLEN, "/block/%s/%s", |
e4dc0e11 KS |
190 | dent->d_name, dent2->d_name); |
191 | filename[MAX_PATHLEN-1] = '\0'; | |
0e306d08 | 192 | device_list_insert(filename, "block", &device_list); |
82b9a637 GKH |
193 | } |
194 | } | |
e13fa599 | 195 | closedir(dir3); |
82b9a637 GKH |
196 | } |
197 | } | |
e13fa599 | 198 | closedir(dir2); |
82b9a637 GKH |
199 | } |
200 | } | |
e13fa599 | 201 | closedir(dir); |
82b9a637 GKH |
202 | } |
203 | ||
0e306d08 GKH |
204 | exec_list(&device_list); |
205 | } | |
206 | ||
207 | static void udev_scan_class(void) | |
208 | { | |
209 | DIR *dir; | |
210 | struct dirent *dent; | |
211 | LIST_HEAD(device_list); | |
212 | ||
213 | dir = opendir(SYSCLASS); | |
e4dc0e11 KS |
214 | if (dir != NULL) { |
215 | for (dent = readdir(dir); dent != NULL; dent = readdir(dir)) { | |
216 | char dirname[MAX_PATHLEN]; | |
217 | DIR *dir2; | |
218 | struct dirent *dent2; | |
219 | ||
220 | if ((strcmp(dent->d_name, ".") == 0) || | |
221 | (strcmp(dent->d_name, "..") == 0)) | |
82b9a637 GKH |
222 | continue; |
223 | ||
0e306d08 | 224 | snprintf(dirname, MAX_PATHLEN, "%s/%s", SYSCLASS, dent->d_name); |
462be028 | 225 | dirname[MAX_PATHLEN-1] = '\0'; |
82b9a637 | 226 | dir2 = opendir(dirname); |
e4dc0e11 KS |
227 | if (dir2 != NULL) { |
228 | for (dent2 = readdir(dir2); dent2 != NULL; dent2 = readdir(dir2)) { | |
a551c7b0 | 229 | char dirname2[MAX_PATHLEN]; |
e4dc0e11 KS |
230 | DIR *dir3; |
231 | struct dirent *dent3; | |
82b9a637 | 232 | |
e4dc0e11 KS |
233 | if ((strcmp(dent2->d_name, ".") == 0) || |
234 | (strcmp(dent2->d_name, "..") == 0)) | |
82b9a637 GKH |
235 | continue; |
236 | ||
aee380b6 KS |
237 | /* pass the net class as it is */ |
238 | if (strcmp(dent->d_name, "net") == 0) { | |
239 | snprintf(dirname2, MAX_PATHLEN, "/class/net/%s", dent2->d_name); | |
240 | device_list_insert(dirname2, "net", &device_list); | |
241 | continue; | |
242 | } | |
243 | ||
82b9a637 | 244 | snprintf(dirname2, MAX_PATHLEN, "%s/%s", dirname, dent2->d_name); |
e4dc0e11 | 245 | dirname2[MAX_PATHLEN-1] = '\0'; |
82b9a637 | 246 | dir3 = opendir(dirname2); |
e4dc0e11 KS |
247 | if (dir3 != NULL) { |
248 | for (dent3 = readdir(dir3); dent3 != NULL; dent3 = readdir(dir3)) { | |
249 | char filename[MAX_PATHLEN]; | |
82b9a637 | 250 | |
aee380b6 | 251 | /* pass devices with a "dev" file */ |
82b9a637 | 252 | if (strcmp(dent3->d_name, "dev") == 0) { |
0e306d08 | 253 | snprintf(filename, MAX_PATHLEN, "/class/%s/%s", |
e4dc0e11 KS |
254 | dent->d_name, dent2->d_name); |
255 | filename[MAX_PATHLEN-1] = '\0'; | |
0e306d08 | 256 | device_list_insert(filename, dent->d_name, &device_list); |
aee380b6 | 257 | break; |
82b9a637 GKH |
258 | } |
259 | } | |
e13fa599 | 260 | closedir(dir3); |
82b9a637 GKH |
261 | } |
262 | } | |
e13fa599 | 263 | closedir(dir2); |
82b9a637 GKH |
264 | } |
265 | } | |
e13fa599 | 266 | closedir(dir); |
82b9a637 | 267 | } |
0e306d08 GKH |
268 | |
269 | exec_list(&device_list); | |
82b9a637 GKH |
270 | } |
271 | ||
eb6c7cd0 | 272 | int udev_start(void) |
82b9a637 | 273 | { |
0e306d08 GKH |
274 | udev_scan_class(); |
275 | udev_scan_block(); | |
3f20eac0 | 276 | return 0; |
82b9a637 | 277 | } |