]>
Commit | Line | Data |
---|---|---|
f0083e3d GKH |
1 | /* |
2 | * udev.c | |
3 | * | |
4 | * Userspace devfs | |
5 | * | |
8202eb32 | 6 | * Copyright (C) 2003,2004 Greg Kroah-Hartman <greg@kroah.com> |
c449b25e | 7 | * Copyright (C) 2004 Kay Sievers <kay.sievers@vrfy.org> |
f0083e3d GKH |
8 | * |
9 | * This program is free software; you can redistribute it and/or modify it | |
10 | * under the terms of the GNU General Public License as published by the | |
11 | * Free Software Foundation version 2 of the License. | |
12 | * | |
13 | * This program is distributed in the hope that it will be useful, but | |
14 | * WITHOUT ANY WARRANTY; without even the implied warranty of | |
15 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | |
16 | * General Public License for more details. | |
17 | * | |
18 | * You should have received a copy of the GNU General Public License along | |
19 | * with this program; if not, write to the Free Software Foundation, Inc., | |
20 | * 675 Mass Ave, Cambridge, MA 02139, USA. | |
21 | * | |
22 | */ | |
23 | ||
c81b35c0 KS |
24 | #include <stdio.h> |
25 | #include <stddef.h> | |
f0083e3d GKH |
26 | #include <stdlib.h> |
27 | #include <string.h> | |
c449b25e | 28 | #include <fcntl.h> |
e8baccca | 29 | #include <ctype.h> |
c81b35c0 | 30 | #include <errno.h> |
d12ecb53 | 31 | #include <signal.h> |
1ceba936 | 32 | #include <unistd.h> |
85511f02 | 33 | |
c80da508 | 34 | #include "libsysfs/sysfs/libsysfs.h" |
63f61c5c | 35 | #include "udev_libc_wrapper.h" |
f0083e3d | 36 | #include "udev.h" |
9af5bb2f | 37 | #include "udev_utils.h" |
f0713480 | 38 | #include "udev_sysfs.h" |
f0083e3d | 39 | #include "udev_version.h" |
e5e322bc | 40 | #include "udev_rules.h" |
02fa9ae5 | 41 | #include "logging.h" |
f0083e3d | 42 | |
6c18b1fb | 43 | #ifdef USE_LOG |
6b493a20 | 44 | void log_message(int priority, const char *format, ...) |
51a8bb2f | 45 | { |
e964c2c0 | 46 | va_list args; |
d026a35d | 47 | |
6b493a20 | 48 | if (priority > udev_log_priority) |
d026a35d GKH |
49 | return; |
50 | ||
51 | va_start(args, format); | |
6b493a20 | 52 | vsyslog(priority, format, args); |
d026a35d | 53 | va_end(args); |
51a8bb2f | 54 | } |
d026a35d | 55 | #endif |
51a8bb2f | 56 | |
eabfc973 KS |
57 | /* decide if we should manage the whole hotplug event |
58 | * for now look if the kernel calls udevsend instead of /sbin/hotplug | |
59 | */ | |
d07557b9 KS |
60 | static int manage_hotplug_event(void) { |
61 | char helper[256]; | |
62 | int fd; | |
63 | int len; | |
64 | ||
eabfc973 KS |
65 | /* don't handle hotplug.d if we are called directly */ |
66 | if (!getenv("UDEVD_EVENT")) | |
67 | return 0; | |
927bda37 | 68 | |
d07557b9 KS |
69 | fd = open("/proc/sys/kernel/hotplug", O_RDONLY); |
70 | if (fd < 0) | |
eabfc973 | 71 | return 0; |
d07557b9 KS |
72 | |
73 | len = read(fd, helper, 256); | |
74 | close(fd); | |
75 | ||
76 | if (len < 0) | |
eabfc973 | 77 | return 0; |
d07557b9 KS |
78 | helper[len] = '\0'; |
79 | ||
80 | if (strstr(helper, "udevsend")) | |
81 | return 1; | |
82 | ||
d07557b9 KS |
83 | return 0; |
84 | } | |
85 | ||
e5a5b54a | 86 | static void asmlinkage sig_handler(int signum) |
d12ecb53 | 87 | { |
d12ecb53 | 88 | switch (signum) { |
7e89a569 | 89 | case SIGALRM: |
2b41e68a | 90 | exit(1); |
d12ecb53 MB |
91 | case SIGINT: |
92 | case SIGTERM: | |
d12ecb53 | 93 | exit(20 + signum); |
d12ecb53 MB |
94 | } |
95 | } | |
96 | ||
aee380b6 | 97 | int main(int argc, char *argv[], char *envp[]) |
f4dc8d11 | 98 | { |
7a947ce5 | 99 | struct sysfs_class_device *class_dev; |
c449b25e | 100 | struct sysfs_device *devices_dev; |
7a947ce5 | 101 | struct udevice udev; |
63f61c5c | 102 | char path[PATH_SIZE]; |
c449b25e | 103 | const char *error; |
8544c9ad KS |
104 | const char *action; |
105 | const char *devpath; | |
106 | const char *subsystem; | |
eabfc973 | 107 | int managed_event; |
03cfa139 | 108 | struct sigaction act; |
8544c9ad | 109 | int retval = -EINVAL; |
f4dc8d11 | 110 | |
51737eb8 KS |
111 | if (argc == 2 && strcmp(argv[1], "-V") == 0) { |
112 | printf("%s\n", UDEV_VERSION); | |
113 | exit(0); | |
114 | } | |
115 | ||
7257cb18 | 116 | logging_init("udev"); |
aee380b6 | 117 | udev_init_config(); |
6b493a20 | 118 | dbg("version %s", UDEV_VERSION); |
af815f88 | 119 | |
47bf9196 | 120 | /* set signal handlers */ |
18ebc430 | 121 | memset(&act, 0x00, sizeof(act)); |
6b493a20 | 122 | act.sa_handler = (void (*)(int)) sig_handler; |
f8911dbb | 123 | sigemptyset (&act.sa_mask); |
5a73b25f | 124 | act.sa_flags = 0; |
7e89a569 | 125 | sigaction(SIGALRM, &act, NULL); |
f8911dbb KS |
126 | sigaction(SIGINT, &act, NULL); |
127 | sigaction(SIGTERM, &act, NULL); | |
3fd52a76 | 128 | |
2af003fe | 129 | /* trigger timeout to prevent hanging processes */ |
7e89a569 KS |
130 | alarm(ALARM_TIMEOUT); |
131 | ||
eabfc973 KS |
132 | /* let the executed programs know if we handle the whole hotplug event */ |
133 | managed_event = manage_hotplug_event(); | |
134 | if (managed_event) | |
135 | setenv("MANAGED_EVENT", "1", 1); | |
136 | ||
7e0bd584 KS |
137 | action = getenv("ACTION"); |
138 | devpath = getenv("DEVPATH"); | |
139 | subsystem = getenv("SUBSYSTEM"); | |
140 | /* older kernels passed the SUBSYSTEM only as argument */ | |
141 | if (!subsystem && argc == 2) | |
142 | subsystem = argv[1]; | |
7e0bd584 | 143 | |
fb39f056 | 144 | udev_init_device(&udev, devpath, subsystem, action); |
03cfa139 KS |
145 | |
146 | if (!action || !subsystem || !devpath) { | |
6b493a20 | 147 | err("action, subsystem or devpath missing"); |
d07557b9 | 148 | goto hotplug; |
c449b25e | 149 | } |
f0713480 | 150 | |
d07557b9 | 151 | /* export logging flag, as called scripts may want to do the same as udev */ |
6b493a20 KS |
152 | if (udev_log_priority) { |
153 | char priority[32]; | |
154 | ||
155 | sprintf(priority, "%i", udev_log_priority); | |
156 | setenv("UDEV_LOG", priority, 1); | |
157 | } | |
c449b25e | 158 | |
e6764498 | 159 | if (udev.type == DEV_BLOCK || udev.type == DEV_CLASS || udev.type == DEV_NET) { |
821d0ec8 KS |
160 | udev_rules_init(); |
161 | ||
c449b25e KS |
162 | if (strcmp(action, "add") == 0) { |
163 | /* wait for sysfs and possibly add node */ | |
164 | dbg("udev add"); | |
165 | ||
9a50eb49 | 166 | /* skip subsystems without "dev", but handle net devices */ |
e6764498 | 167 | if (udev.type != DEV_NET && subsystem_expect_no_dev(udev.subsystem)) { |
c449b25e | 168 | dbg("don't care about '%s' devices", udev.subsystem); |
d07557b9 | 169 | goto hotplug; |
9a50eb49 | 170 | } |
c449b25e | 171 | |
63f61c5c KS |
172 | snprintf(path, sizeof(path), "%s%s", sysfs_path, udev.devpath); |
173 | path[sizeof(path)-1] = '\0'; | |
c449b25e KS |
174 | class_dev = wait_class_device_open(path); |
175 | if (class_dev == NULL) { | |
6b493a20 | 176 | dbg("open class device failed"); |
d07557b9 | 177 | goto hotplug; |
c449b25e KS |
178 | } |
179 | dbg("opened class_dev->name='%s'", class_dev->name); | |
180 | ||
181 | wait_for_class_device(class_dev, &error); | |
182 | ||
c449b25e KS |
183 | /* name, create node, store in db */ |
184 | retval = udev_add_device(&udev, class_dev); | |
185 | ||
c449b25e KS |
186 | sysfs_close_class_device(class_dev); |
187 | } else if (strcmp(action, "remove") == 0) { | |
188 | /* possibly remove a node */ | |
189 | dbg("udev remove"); | |
190 | ||
9a50eb49 KS |
191 | /* skip subsystems without "dev" */ |
192 | if (subsystem_expect_no_dev(udev.subsystem)) { | |
193 | dbg("don't care about '%s' devices", udev.subsystem); | |
194 | goto hotplug; | |
195 | } | |
196 | ||
821d0ec8 KS |
197 | udev_rules_get_run(&udev); |
198 | if (udev.ignore_device) { | |
199 | dbg("device event will be ignored"); | |
200 | goto hotplug; | |
201 | } | |
202 | ||
d07557b9 | 203 | /* get node from db, remove db-entry, delete created node */ |
c449b25e | 204 | retval = udev_remove_device(&udev); |
9a50eb49 | 205 | } |
c449b25e | 206 | |
81af4e05 KS |
207 | if (udev.devname[0] != '\0') |
208 | setenv("DEVNAME", udev.devname, 1); | |
209 | ||
821d0ec8 KS |
210 | if (udev_run && !list_empty(&udev.run_list)) { |
211 | struct name_entry *name_loop; | |
212 | ||
213 | dbg("executing run list"); | |
214 | list_for_each_entry(name_loop, &udev.run_list, node) | |
215 | execute_command(name_loop->name, udev.subsystem); | |
216 | } | |
217 | ||
9a50eb49 | 218 | /* run dev.d/ scripts if we created/deleted a node or changed a netif name */ |
81af4e05 KS |
219 | if (udev_dev_d && udev.devname[0] != '\0') |
220 | udev_multiplex_directory(&udev, DEVD_DIR, DEVD_SUFFIX); | |
221 | ||
e6764498 | 222 | } else if (udev.type == DEV_DEVICE) { |
c449b25e KS |
223 | if (strcmp(action, "add") == 0) { |
224 | /* wait for sysfs */ | |
225 | dbg("devices add"); | |
5d24c6ca | 226 | |
63f61c5c KS |
227 | snprintf(path, sizeof(path), "%s%s", sysfs_path, devpath); |
228 | path[sizeof(path)-1] = '\0'; | |
c449b25e KS |
229 | devices_dev = wait_devices_device_open(path); |
230 | if (!devices_dev) { | |
231 | dbg("devices device unavailable (probably remove has beaten us)"); | |
d07557b9 | 232 | goto hotplug; |
c449b25e KS |
233 | } |
234 | dbg("devices device opened '%s'", path); | |
5d24c6ca | 235 | |
c449b25e | 236 | wait_for_devices_device(devices_dev, &error); |
5d24c6ca | 237 | |
c449b25e KS |
238 | sysfs_close_device(devices_dev); |
239 | } else if (strcmp(action, "remove") == 0) { | |
240 | dbg("devices remove"); | |
a97b0648 | 241 | } |
c449b25e KS |
242 | } else { |
243 | dbg("unhandled"); | |
dbfc520c | 244 | } |
2a94c877 | 245 | |
d07557b9 | 246 | hotplug: |
eabfc973 | 247 | if (udev_hotplug_d && managed_event) |
9af5bb2f | 248 | udev_multiplex_directory(&udev, HOTPLUGD_DIR, HOTPLUG_SUFFIX); |
d07557b9 | 249 | |
fb39f056 KS |
250 | udev_cleanup_device(&udev); |
251 | ||
7257cb18 | 252 | logging_close(); |
f61d732a | 253 | return retval; |
f0083e3d | 254 | } |