]>
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 | ||
0e306d08 GKH |
89 | static void exec_list(struct list_head *device_list) |
90 | { | |
91 | struct device *loop_device; | |
92 | struct device *tmp_device; | |
70f630f6 GKH |
93 | int i; |
94 | ||
95 | /* handle the "first" type devices first */ | |
96 | list_for_each_entry_safe(loop_device, tmp_device, device_list, list) { | |
97 | for (i=0; first_list[i] != NULL; i++) { | |
98 | if (strncmp(loop_device->path, first_list[i], strlen(first_list[i])) == 0) { | |
99 | udev_add_device(loop_device->path, loop_device->subsys, NOFAKE); | |
100 | list_del(&loop_device->list); | |
101 | free(loop_device); | |
102 | break; | |
103 | } | |
104 | } | |
105 | } | |
0e306d08 GKH |
106 | |
107 | /* handle the devices we are allowed to, excluding the "last" type devices */ | |
108 | list_for_each_entry_safe(loop_device, tmp_device, device_list, list) { | |
109 | int found = 0; | |
0e306d08 GKH |
110 | for (i=0; last_list[i] != NULL; i++) { |
111 | if (strncmp(loop_device->path, last_list[i], strlen(last_list[i])) == 0) { | |
112 | found = 1; | |
113 | break; | |
114 | } | |
115 | } | |
116 | if (found) | |
117 | continue; | |
118 | ||
aee380b6 | 119 | udev_add_device(loop_device->path, loop_device->subsys, NOFAKE); |
0e306d08 GKH |
120 | list_del(&loop_device->list); |
121 | free(loop_device); | |
122 | } | |
123 | ||
124 | /* handle the rest of the devices left over, if any */ | |
125 | list_for_each_entry_safe(loop_device, tmp_device, device_list, list) { | |
aee380b6 | 126 | udev_add_device(loop_device->path, loop_device->subsys, NOFAKE); |
0e306d08 GKH |
127 | list_del(&loop_device->list); |
128 | free(loop_device); | |
129 | } | |
130 | } | |
131 | ||
132 | static void udev_scan_block(void) | |
82b9a637 | 133 | { |
e4dc0e11 KS |
134 | DIR *dir; |
135 | struct dirent *dent; | |
0e306d08 | 136 | LIST_HEAD(device_list); |
82b9a637 | 137 | |
0e306d08 | 138 | dir = opendir(SYSBLOCK); |
e4dc0e11 KS |
139 | if (dir != NULL) { |
140 | for (dent = readdir(dir); dent != NULL; dent = readdir(dir)) { | |
141 | char dirname[MAX_PATHLEN]; | |
142 | DIR *dir2; | |
143 | struct dirent *dent2; | |
144 | ||
145 | if ((strcmp(dent->d_name, ".") == 0) || | |
146 | (strcmp(dent->d_name, "..") == 0)) | |
82b9a637 GKH |
147 | continue; |
148 | ||
0e306d08 GKH |
149 | snprintf(dirname, MAX_PATHLEN, "/block/%s", dent->d_name); |
150 | dirname[MAX_PATHLEN-1] = '\0'; | |
151 | device_list_insert(dirname, "block", &device_list); | |
152 | ||
153 | snprintf(dirname, MAX_PATHLEN, "%s/%s", SYSBLOCK, dent->d_name); | |
82b9a637 | 154 | dir2 = opendir(dirname); |
e4dc0e11 KS |
155 | if (dir2 != NULL) { |
156 | for (dent2 = readdir(dir2); dent2 != NULL; dent2 = readdir(dir2)) { | |
0e306d08 | 157 | char dirname2[MAX_PATHLEN]; |
e4dc0e11 KS |
158 | DIR *dir3; |
159 | struct dirent *dent3; | |
82b9a637 GKH |
160 | |
161 | if ((strcmp(dent2->d_name, ".") == 0) || | |
162 | (strcmp(dent2->d_name, "..") == 0)) | |
163 | continue; | |
164 | ||
165 | snprintf(dirname2, MAX_PATHLEN, "%s/%s", dirname, dent2->d_name); | |
e4dc0e11 | 166 | dirname2[MAX_PATHLEN-1] = '\0'; |
82b9a637 GKH |
167 | |
168 | dir3 = opendir(dirname2); | |
e4dc0e11 KS |
169 | if (dir3 != NULL) { |
170 | for (dent3 = readdir(dir3); dent3 != NULL; dent3 = readdir(dir3)) { | |
82b9a637 GKH |
171 | char filename[MAX_PATHLEN]; |
172 | ||
173 | if (strcmp(dent3->d_name, "dev") == 0) { | |
0e306d08 | 174 | snprintf(filename, MAX_PATHLEN, "/block/%s/%s", |
e4dc0e11 KS |
175 | dent->d_name, dent2->d_name); |
176 | filename[MAX_PATHLEN-1] = '\0'; | |
0e306d08 | 177 | device_list_insert(filename, "block", &device_list); |
82b9a637 GKH |
178 | } |
179 | } | |
e13fa599 | 180 | closedir(dir3); |
82b9a637 GKH |
181 | } |
182 | } | |
e13fa599 | 183 | closedir(dir2); |
82b9a637 GKH |
184 | } |
185 | } | |
e13fa599 | 186 | closedir(dir); |
82b9a637 GKH |
187 | } |
188 | ||
0e306d08 GKH |
189 | exec_list(&device_list); |
190 | } | |
191 | ||
192 | static void udev_scan_class(void) | |
193 | { | |
194 | DIR *dir; | |
195 | struct dirent *dent; | |
196 | LIST_HEAD(device_list); | |
197 | ||
198 | dir = opendir(SYSCLASS); | |
e4dc0e11 KS |
199 | if (dir != NULL) { |
200 | for (dent = readdir(dir); dent != NULL; dent = readdir(dir)) { | |
201 | char dirname[MAX_PATHLEN]; | |
202 | DIR *dir2; | |
203 | struct dirent *dent2; | |
204 | ||
205 | if ((strcmp(dent->d_name, ".") == 0) || | |
206 | (strcmp(dent->d_name, "..") == 0)) | |
82b9a637 GKH |
207 | continue; |
208 | ||
0e306d08 | 209 | snprintf(dirname, MAX_PATHLEN, "%s/%s", SYSCLASS, dent->d_name); |
462be028 | 210 | dirname[MAX_PATHLEN-1] = '\0'; |
82b9a637 | 211 | dir2 = opendir(dirname); |
e4dc0e11 KS |
212 | if (dir2 != NULL) { |
213 | for (dent2 = readdir(dir2); dent2 != NULL; dent2 = readdir(dir2)) { | |
0e306d08 | 214 | char dirname2[MAX_PATHLEN-1]; |
e4dc0e11 KS |
215 | DIR *dir3; |
216 | struct dirent *dent3; | |
82b9a637 | 217 | |
e4dc0e11 KS |
218 | if ((strcmp(dent2->d_name, ".") == 0) || |
219 | (strcmp(dent2->d_name, "..") == 0)) | |
82b9a637 GKH |
220 | continue; |
221 | ||
aee380b6 KS |
222 | /* pass the net class as it is */ |
223 | if (strcmp(dent->d_name, "net") == 0) { | |
224 | snprintf(dirname2, MAX_PATHLEN, "/class/net/%s", dent2->d_name); | |
225 | device_list_insert(dirname2, "net", &device_list); | |
226 | continue; | |
227 | } | |
228 | ||
82b9a637 | 229 | snprintf(dirname2, MAX_PATHLEN, "%s/%s", dirname, dent2->d_name); |
e4dc0e11 | 230 | dirname2[MAX_PATHLEN-1] = '\0'; |
82b9a637 | 231 | dir3 = opendir(dirname2); |
e4dc0e11 KS |
232 | if (dir3 != NULL) { |
233 | for (dent3 = readdir(dir3); dent3 != NULL; dent3 = readdir(dir3)) { | |
234 | char filename[MAX_PATHLEN]; | |
82b9a637 | 235 | |
aee380b6 | 236 | /* pass devices with a "dev" file */ |
82b9a637 | 237 | if (strcmp(dent3->d_name, "dev") == 0) { |
0e306d08 | 238 | snprintf(filename, MAX_PATHLEN, "/class/%s/%s", |
e4dc0e11 KS |
239 | dent->d_name, dent2->d_name); |
240 | filename[MAX_PATHLEN-1] = '\0'; | |
0e306d08 | 241 | device_list_insert(filename, dent->d_name, &device_list); |
aee380b6 | 242 | break; |
82b9a637 GKH |
243 | } |
244 | } | |
e13fa599 | 245 | closedir(dir3); |
82b9a637 GKH |
246 | } |
247 | } | |
e13fa599 | 248 | closedir(dir2); |
82b9a637 GKH |
249 | } |
250 | } | |
e13fa599 | 251 | closedir(dir); |
82b9a637 | 252 | } |
0e306d08 GKH |
253 | |
254 | exec_list(&device_list); | |
82b9a637 GKH |
255 | } |
256 | ||
eb6c7cd0 | 257 | int udev_start(void) |
82b9a637 | 258 | { |
0e306d08 GKH |
259 | udev_scan_class(); |
260 | udev_scan_block(); | |
3f20eac0 | 261 | return 0; |
82b9a637 | 262 | } |