hotplug2: patches from OpenWRT/svn
[tomato.git] / release / src / router / hotplug2 / linux24_compat / hotplug2-coldplug-2.4.c
blob10ccb80590363d0402152b4888f294b0137f8db5
1 /*****************************************************************************\
2 * _ _ _ _ ___ *
3 * | || | ___ | |_ _ __ | | _ _ __ _ |_ ) *
4 * | __ |/ _ \| _|| '_ \| || || |/ _` | / / *
5 * |_||_|\___/ \__|| .__/|_| \_,_|\__, |/___| *
6 * |_| |___/ *
7 \*****************************************************************************/
9 #define _GNU_SOURCE
11 #include <fcntl.h>
12 #include <stdio.h>
13 #include <unistd.h>
14 #include <stdlib.h>
15 #include <errno.h>
16 #include <dirent.h>
17 #include <ctype.h>
18 #include <sys/socket.h>
19 #include <sys/types.h>
20 #include <sys/un.h>
21 #include <sys/wait.h>
22 #include <sys/stat.h>
23 #include <sys/mman.h>
24 #include <linux/types.h>
25 #include <linux/netlink.h>
27 #include "../hotplug2.h"
28 #include "../mem_utils.h"
29 #include "../parser_utils.h"
30 #include "../filemap_utils.h"
31 #include "../hotplug2_utils.h"
33 inline char *get_uevent_string(char **environ, unsigned long *uevent_string_len) {
34 char *uevent_string;
35 char *tmp;
36 unsigned long offset;
38 *uevent_string_len = 4;
39 offset = *uevent_string_len - 1;
40 uevent_string = xmalloc(*uevent_string_len);
41 strcpy(uevent_string, "add");
42 uevent_string[offset] = '@';
43 offset++;
45 for (; *environ != NULL; environ++) {
46 *uevent_string_len += strlen(*environ) + 1;
47 uevent_string = xrealloc(uevent_string, *uevent_string_len);
48 strcpy(&uevent_string[offset], *environ);
49 offset = *uevent_string_len;
52 /* 64 + 7 ('SEQNUM=') + 1 ('\0') */
53 tmp = xmalloc(72);
54 memset(tmp, 0, 72);
55 snprintf(tmp, 72, "SEQNUM=%llu", get_kernel_seqnum());
57 *uevent_string_len += strlen(tmp) + 1;
58 uevent_string = xrealloc(uevent_string, *uevent_string_len);
59 strcpy(&uevent_string[offset], tmp);
60 offset = *uevent_string_len;
62 free(tmp);
64 return uevent_string;
67 int dispatch_event(int netlink_socket, char **environ) {
68 char *uevent_string;
69 unsigned long uevent_string_len;
71 uevent_string = get_uevent_string(environ, &uevent_string_len);
72 if (uevent_string == NULL) {
73 ERROR("dispatch_event", "Unable to create uevent string.");
74 return 1;
77 if (send(netlink_socket, uevent_string, uevent_string_len, 0) == -1) {
78 ERROR("dispatch_event","send failed: %s.", strerror(errno));
79 free(uevent_string);
80 return 1;
83 free(uevent_string);
85 return 0;
88 char *join_to_fourhex(unsigned char hex0, unsigned char hex1) {
89 char *tmp;
91 tmp = xmalloc(5);
92 if (hex0 != 0) {
93 snprintf(tmp, 4, "%x%2x", hex0, hex1);
94 } else {
95 snprintf(tmp, 4, "%x", hex1);
98 return tmp;
101 void generate_pci_events(int netlink_socket) {
102 unsigned char pci_desc_info[256];
103 char pci_dir_name[256];
104 char pci_dev_name[512];
106 char **environ;
107 int i;
109 DIR *procdir, *pcidir;
110 FILE *item;
111 struct dirent *cur_bus, *cur_device;
113 procdir = opendir("/proc/bus/pci");
114 if (procdir == NULL) {
115 ERROR("pci coldplug", "Unable to open procfs PCI interface.");
116 return;
119 while ((cur_bus = readdir(procdir)) != NULL) {
120 if (cur_bus->d_type != DT_DIR)
121 continue;
123 if (cur_bus->d_name[0] == '.')
124 continue;
126 memset(pci_dir_name, 0, 256);
127 snprintf(pci_dir_name, 255, "/proc/bus/pci/%s", cur_bus->d_name);
128 pcidir = opendir(pci_dir_name);
130 while ((cur_device = readdir(pcidir)) != NULL) {
131 if (cur_device->d_type != DT_REG)
132 continue;
134 if (cur_device->d_name[0] == '.')
135 continue;
137 memset(pci_dev_name, 0, 256);
138 snprintf(pci_dev_name, 511, "/proc/bus/pci/%s/%s", cur_bus->d_name, cur_device->d_name);
139 item = fopen(pci_dev_name, "rb");
141 if (item == NULL) {
142 ERROR("pci coldplug", "Missing PCI entry.");
143 continue;
146 fread(pci_desc_info, 256, 1, item);
147 fclose(item);
150 environ = xmalloc(sizeof(char*) * 8);
151 environ[0] = NULL;
152 environ[1] = NULL;
153 environ[2] = NULL;
154 environ[3] = NULL;
155 environ[4] = NULL;
156 environ[5] = NULL;
157 environ[6] = NULL;
158 environ[7] = NULL;
160 environ[0] = strdup("ACTION=add");
161 environ[1] = strdup("SUBSYSTEM=pci");
163 environ[2] = xmalloc(21 + strlen(cur_bus->d_name) + strlen(cur_device->d_name));
164 strcpy(environ[2], "PCI_SLOT_NAME=0000:");
165 strcat(environ[2], cur_bus->d_name);
166 strcat(environ[2], ":");
167 strcat(environ[2], cur_device->d_name);
169 environ[3] = xmalloc(17);
170 snprintf(environ[3], 17, "PCI_ID=%02X%02X:%02X%02X", pci_desc_info[1], pci_desc_info[0], pci_desc_info[3], pci_desc_info[2]);
172 environ[4] = xmalloc(24);
173 snprintf(environ[4], 24, "PCI_SUBSYS_ID=%02X%02X:%02X%02X", pci_desc_info[45], pci_desc_info[44], pci_desc_info[47], pci_desc_info[46]);
175 environ[5] = xmalloc(17);
176 snprintf(environ[5], 17, "PCI_CLASS=%x%02X%02X", pci_desc_info[11], pci_desc_info[10], pci_desc_info[9]);
178 environ[6] = xmalloc(64);
179 snprintf(environ[6], 64, "MODALIAS=pci:v0000%02X%02Xd0000%02X%02Xsv0000%02X%02Xsd0000%02X%02Xbc%02Xsc%02Xi%02X",
180 pci_desc_info[1], pci_desc_info[0], pci_desc_info[3], pci_desc_info[2],
181 pci_desc_info[45], pci_desc_info[44], pci_desc_info[47], pci_desc_info[46],
182 pci_desc_info[11], pci_desc_info[10], pci_desc_info[9]);
184 dispatch_event(netlink_socket, environ);
186 for (i = 0; environ[i] != NULL; i++)
187 free(environ[i]);
188 free(environ);
191 closedir(pcidir);
194 closedir(procdir);
197 void generate_usb_events(int netlink_socket) {
198 unsigned char usb_desc_info[52];
199 char usb_dir_name[256];
200 char usb_dev_name[512];
202 char **environ;
203 char *t1, *t2, *t3;
204 int i;
206 DIR *procdir, *usbdir;
207 FILE *item;
208 struct dirent *cur_bus, *cur_device;
210 procdir = opendir("/proc/bus/usb");
211 if (procdir == NULL) {
212 ERROR("usb coldplug", "Unable to open procfs usb interface.");
213 return;
216 while ((cur_bus = readdir(procdir)) != NULL) {
217 if (cur_bus->d_type != DT_DIR)
218 continue;
220 if (cur_bus->d_name[0] == '.')
221 continue;
223 memset(usb_dir_name, 0, 256);
224 snprintf(usb_dir_name, 255, "/proc/bus/usb/%s", cur_bus->d_name);
225 usbdir = opendir(usb_dir_name);
227 while ((cur_device = readdir(usbdir)) != NULL) {
228 if (cur_device->d_type != DT_REG)
229 continue;
231 if (cur_device->d_name[0] == '.')
232 continue;
234 memset(usb_dev_name, 0, 256);
235 snprintf(usb_dev_name, 511, "/proc/bus/usb/%s/%s", cur_bus->d_name, cur_device->d_name);
236 item = fopen(usb_dev_name, "rb");
238 if (item == NULL) {
239 ERROR("usb coldplug", "Missing usb entry.");
240 continue;
243 fread(usb_desc_info, 52, 1, item);
244 fclose(item);
246 environ = xmalloc(sizeof(char*) * 8);
247 environ[7] = NULL;
249 environ[0] = strdup("ACTION=add");
250 environ[1] = strdup("SUBSYSTEM=usb");
252 environ[2] = xmalloc(8 + strlen(usb_dev_name));
253 strcpy(environ[2], "DEVICE=");
254 strcat(environ[2], usb_dev_name);
256 environ[3] = xmalloc(24);
257 memset(environ[3], 0, 24);
258 t1 = join_to_fourhex(usb_desc_info[9], usb_desc_info[8]);
259 t2 = join_to_fourhex(usb_desc_info[11], usb_desc_info[10]);
260 t3 = join_to_fourhex(usb_desc_info[13], usb_desc_info[12]);
262 snprintf(environ[3], 23, "PRODUCT=%s/%s/%s", t1, t2, t3);
264 free(t1); free(t2); free(t3);
266 environ[4] = xmalloc(14);
267 memset(environ[4], 0, 14);
268 snprintf(environ[4], 13, "TYPE=%x/%x/%x", usb_desc_info[4], usb_desc_info[5], usb_desc_info[6]);
270 environ[5] = xmalloc(55);
271 memset(environ[5], 0, 55);
273 if (usb_desc_info[32] != 0x0 && usb_desc_info[33] != 0x0 && usb_desc_info[34] != 0x0) {
274 snprintf(environ[5], 55, "MODALIAS=usb:v%02X%02Xp%02X%02Xd%02X%02Xdc%02Xdsc%02Xdp%02Xic%02Xisc%02Xip%02X",
275 usb_desc_info[9], usb_desc_info[8], usb_desc_info[11], usb_desc_info[10], usb_desc_info[13], usb_desc_info[12],
276 usb_desc_info[4], usb_desc_info[5], usb_desc_info[6],
277 usb_desc_info[32], usb_desc_info[33], usb_desc_info[34]);
279 environ[6] = xmalloc(24);
280 memset(environ[6], 0, 24);
281 snprintf(environ[6], 24, "INTERFACE=%x/%x/%x", usb_desc_info[32], usb_desc_info[33], usb_desc_info[34]);
282 } else {
283 snprintf(environ[5], 55, "MODALIAS=usb:v%02X%02Xp%02X%02Xd%02X%02Xdc%02Xdsc%02Xdp%02Xic*isc*ip*",
284 usb_desc_info[9], usb_desc_info[8], usb_desc_info[11], usb_desc_info[10], usb_desc_info[13], usb_desc_info[12],
285 usb_desc_info[4], usb_desc_info[5], usb_desc_info[6]);
287 environ[6] = NULL;
290 dispatch_event(netlink_socket, environ);
292 for (i = 0; environ[i] != NULL; i++)
293 free(environ[i]);
294 free(environ);
297 closedir(usbdir);
300 closedir(procdir);
303 void generate_isapnp_events(int netlink_socket) {
304 struct filemap_t isapnpmap;
305 char **environ;
306 char *line, *nline, *nptr;
307 char *token;
308 char *device;
309 int i;
311 if (map_file("/proc/bus/isapnp/devices", &isapnpmap)) {
312 ERROR("isapnp coldplug", "Unable to open procfs isapnp interface.");
313 return;
316 nptr = isapnpmap.map;
318 while ((line = dup_line(nptr, &nptr)) != NULL) {
319 nline = line;
320 token = dup_token(nline, &nline, isspace);
321 if (!token)
322 continue;
323 free(token);
325 token = dup_token(nline, &nline, isspace);
326 if (!token)
327 continue;
329 if (strlen(token) < 14) {
330 free(token);
331 continue;
334 environ = xmalloc(sizeof(char*) * 4);
335 environ[3] = NULL;
337 environ[0] = strdup("ACTION=add");
338 environ[1] = strdup("SUBSYSTEM=pnp");
340 environ[2] = xmalloc(14);
341 strcpy(environ[2], "MODALIAS=pnp:");
342 for (device = &token[7]; *device != '\0'; device += 7) {
343 environ[2] = xrealloc(environ[2], 14 + device - token);
344 memcpy(environ[2] + (device - token) + 6, device, 7);
345 environ[2][13 + device - token] = '\0';
348 dispatch_event(netlink_socket, environ);
350 for (i = 0; environ[i] != NULL; i++)
351 free(environ[i]);
352 free(environ);
354 free(token);
355 free(line);
358 unmap_file(&isapnpmap);
361 int main(int argc, char *argv[], char **environ) {
362 int netlink_socket;
364 netlink_socket = init_netlink_socket(NETLINK_CONNECT);
365 if (netlink_socket == -1) {
366 ERROR("netlink init","Unable to open netlink socket.");
367 return 1;
370 generate_pci_events(netlink_socket);
371 generate_usb_events(netlink_socket);
372 generate_isapnp_events(netlink_socket);
374 close(netlink_socket);
375 return 0;