2 * quick and dirty way to populate a /dev directory
4 * Copyright (C) 2004 Harald Hoyer <harald@redhat.com>
5 * Copyright (C) 2004 Greg Kroah-Hartman <greg@kroah.com>
6 * Copyright (C) 2004-2006 Kay Sievers <kay@vrfy.org>
8 * This program is free software; you can redistribute it and/or modify it
9 * under the terms of the GNU General Public License as published by the
10 * Free Software Foundation version 2 of the License.
12 * This program is distributed in the hope that it will be useful, but
13 * WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 * General Public License for more details.
17 * You should have received a copy of the GNU General Public License along
18 * with this program; if not, write to the Free Software Foundation, Inc.,
19 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
35 #include <sys/types.h>
38 #include "udev_rules.h"
39 #include "udev_selinux.h"
41 static const char *udev_run_str
;
42 static const char *udev_log_str
;
43 static struct udev_rules rules
;
46 void log_message(int priority
, const char *format
, ...)
50 if (priority
> udev_log_priority
)
53 va_start(args
, format
);
54 vsyslog(priority
, format
, args
);
60 struct list_head node
;
64 /* sort files in lexical order */
65 static int device_list_insert(const char *path
, struct list_head
*device_list
)
67 struct device
*loop_device
;
68 struct device
*new_device
;
69 const char *devpath
= &path
[strlen(sysfs_path
)];
71 dbg("insert: '%s'", devpath
);
73 list_for_each_entry(loop_device
, device_list
, node
) {
74 if (strcmp(loop_device
->path
, devpath
) > 0) {
79 new_device
= malloc(sizeof(struct device
));
80 if (new_device
== NULL
) {
85 strlcpy(new_device
->path
, devpath
, sizeof(new_device
->path
));
86 list_add_tail(&new_device
->node
, &loop_device
->node
);
87 dbg("add '%s'" , new_device
->path
);
91 /* list of devices that we should run last due to any one of a number of reasons */
92 static char *last_list
[] = {
93 "/block/dm", /* on here because dm wants to have the block devices around before it */
97 /* list of devices that we should run first due to any one of a number of reasons */
98 static char *first_list
[] = {
104 static int add_device(const char *devpath
)
106 struct sysfs_device
*dev
;
107 struct udevice
*udev
;
110 /* clear and set environment for next event */
112 setenv("ACTION", "add", 1);
113 setenv("UDEV_START", "1", 1);
115 setenv("UDEV_LOG", udev_log_str
, 1);
117 setenv("UDEV_RUN", udev_run_str
, 1);
119 dev
= sysfs_device_get(devpath
);
123 udev
= udev_device_init(NULL
);
127 /* override built-in sysfs device */
129 strcpy(udev
->action
, "add");
131 if (strcmp(udev
->dev
->subsystem
, "net") != 0) {
132 udev
->devt
= udev_device_get_devt(udev
);
133 if (major(udev
->devt
) == 0)
137 dbg("add '%s'", udev
->dev
->devpath
);
138 setenv("DEVPATH", udev
->dev
->devpath
, 1);
139 setenv("SUBSYSTEM", udev
->dev
->subsystem
, 1);
141 udev_rules_get_name(&rules
, udev
);
142 if (udev
->ignore_device
) {
143 dbg("device event will be ignored");
146 if (udev
->name
[0] != '\0')
147 retval
= udev_device_event(&rules
, udev
);
149 info("device node creation supressed");
151 if (retval
== 0 && udev_run
) {
152 struct name_entry
*name_loop
;
154 dbg("executing run list");
155 list_for_each_entry(name_loop
, &udev
->run_list
, node
) {
156 if (strncmp(name_loop
->name
, "socket:", strlen("socket:")) == 0)
157 pass_env_to_socket(&name_loop
->name
[strlen("socket:")], udev
->dev
->devpath
, "add");
159 char program
[PATH_SIZE
];
161 strlcpy(program
, name_loop
->name
, sizeof(program
));
162 udev_rules_apply_format(udev
, program
, sizeof(program
));
163 run_program(program
, udev
->dev
->subsystem
, NULL
, 0, NULL
, (udev_log_priority
>= LOG_INFO
));
169 udev_device_cleanup(udev
);
173 static void exec_list(struct list_head
*device_list
)
175 struct device
*loop_device
;
176 struct device
*tmp_device
;
179 /* handle the "first" type devices first */
180 list_for_each_entry_safe(loop_device
, tmp_device
, device_list
, node
) {
181 for (i
= 0; first_list
[i
] != NULL
; i
++) {
182 if (strncmp(loop_device
->path
, first_list
[i
], strlen(first_list
[i
])) == 0) {
183 add_device(loop_device
->path
);
184 list_del(&loop_device
->node
);
191 /* handle the devices we are allowed to, excluding the "last" type devices */
192 list_for_each_entry_safe(loop_device
, tmp_device
, device_list
, node
) {
194 for (i
= 0; last_list
[i
] != NULL
; i
++) {
195 if (strncmp(loop_device
->path
, last_list
[i
], strlen(last_list
[i
])) == 0) {
203 add_device(loop_device
->path
);
204 list_del(&loop_device
->node
);
208 /* handle the rest of the devices left over, if any */
209 list_for_each_entry_safe(loop_device
, tmp_device
, device_list
, node
) {
210 add_device(loop_device
->path
);
211 list_del(&loop_device
->node
);
216 static int has_devt(const char *path
)
218 char filename
[PATH_SIZE
];
221 snprintf(filename
, sizeof(filename
), "%s/dev", path
);
222 filename
[sizeof(filename
)-1] = '\0';
224 if (stat(filename
, &statbuf
) == 0)
230 static void udev_scan_block(struct list_head
*device_list
)
232 char base
[PATH_SIZE
];
236 snprintf(base
, sizeof(base
), "%s/block", sysfs_path
);
237 base
[sizeof(base
)-1] = '\0';
241 for (dent
= readdir(dir
); dent
!= NULL
; dent
= readdir(dir
)) {
242 char dirname
[PATH_SIZE
];
244 struct dirent
*dent2
;
246 if (dent
->d_name
[0] == '.')
249 snprintf(dirname
, sizeof(dirname
), "%s/%s", base
, dent
->d_name
);
250 dirname
[sizeof(dirname
)-1] = '\0';
251 if (has_devt(dirname
))
252 device_list_insert(dirname
, device_list
);
256 /* look for partitions */
257 dir2
= opendir(dirname
);
259 for (dent2
= readdir(dir2
); dent2
!= NULL
; dent2
= readdir(dir2
)) {
260 char dirname2
[PATH_SIZE
];
262 if (dent2
->d_name
[0] == '.')
265 snprintf(dirname2
, sizeof(dirname2
), "%s/%s", dirname
, dent2
->d_name
);
266 dirname2
[sizeof(dirname2
)-1] = '\0';
268 if (has_devt(dirname2
))
269 device_list_insert(dirname2
, device_list
);
278 static void udev_scan_class(struct list_head
*device_list
)
280 char base
[PATH_SIZE
];
284 snprintf(base
, sizeof(base
), "%s/class", sysfs_path
);
285 base
[sizeof(base
)-1] = '\0';
289 for (dent
= readdir(dir
); dent
!= NULL
; dent
= readdir(dir
)) {
290 char dirname
[PATH_SIZE
];
292 struct dirent
*dent2
;
294 if (dent
->d_name
[0] == '.')
297 snprintf(dirname
, sizeof(dirname
), "%s/%s", base
, dent
->d_name
);
298 dirname
[sizeof(dirname
)-1] = '\0';
300 dir2
= opendir(dirname
);
302 for (dent2
= readdir(dir2
); dent2
!= NULL
; dent2
= readdir(dir2
)) {
303 char dirname2
[PATH_SIZE
];
305 if (dent2
->d_name
[0] == '.')
308 snprintf(dirname2
, sizeof(dirname2
), "%s/%s", dirname
, dent2
->d_name
);
309 dirname2
[sizeof(dirname2
)-1] = '\0';
311 if (has_devt(dirname2
) || strcmp(dent
->d_name
, "net") == 0)
312 device_list_insert(dirname2
, device_list
);
321 static void asmlinkage
sig_handler(int signum
)
332 int main(int argc
, char *argv
[], char *envp
[])
334 LIST_HEAD(device_list
);
335 struct sigaction act
;
337 logging_init("udevstart");
340 dbg("version %s", UDEV_VERSION
);
342 udev_run_str
= getenv("UDEV_RUN");
343 udev_log_str
= getenv("UDEV_LOG");
345 /* disable all logging if not explicitely requested */
346 if (udev_log_str
== NULL
)
347 udev_log_priority
= 0;
349 /* set signal handlers */
350 memset(&act
, 0x00, sizeof(act
));
351 act
.sa_handler
= (void (*) (int))sig_handler
;
352 sigemptyset (&act
.sa_mask
);
354 sigaction(SIGALRM
, &act
, NULL
);
355 sigaction(SIGINT
, &act
, NULL
);
356 sigaction(SIGTERM
, &act
, NULL
);
358 /* trigger timeout to prevent hanging processes */
359 alarm(UDEV_ALARM_TIMEOUT
);
362 udev_rules_init(&rules
, 1);
364 udev_scan_class(&device_list
);
365 udev_scan_block(&device_list
);
366 exec_list(&device_list
);
368 udev_rules_cleanup(&rules
);