1/*****************************************************************************\ 2* _ _ _ _ ___ * 3* | || | ___ | |_ _ __ | | _ _ __ _ |_ ) * 4* | __ |/ _ \| _|| '_ \| || || |/ _` | / / * 5* |_||_|\___/ \__|| .__/|_| \_,_|\__, |/___| * 6* |_| |___/ * 7\*****************************************************************************/ 8 9#define _GNU_SOURCE 10 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> 26 27#include "../hotplug2.h" 28#include "../mem_utils.h" 29#include "../parser_utils.h" 30#include "../filemap_utils.h" 31#include "../hotplug2_utils.h" 32 33inline char *get_uevent_string(char **environ, unsigned long *uevent_string_len) { 34 char *uevent_string; 35 char *tmp; 36 unsigned long offset; 37 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++; 44 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; 50 } 51 52 /* 64 + 7 ('SEQNUM=') + 1 ('\0') */ 53 tmp = xmalloc(72); 54 memset(tmp, 0, 72); 55 snprintf(tmp, 72, "SEQNUM=%llu", get_kernel_seqnum()); 56 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; 61 62 free(tmp); 63 64 return uevent_string; 65} 66 67int dispatch_event(int netlink_socket, char **environ) { 68 char *uevent_string; 69 unsigned long uevent_string_len; 70 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; 75 } 76 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; 81 } 82 83 free(uevent_string); 84 85 return 0; 86} 87 88char *join_to_fourhex(unsigned char hex0, unsigned char hex1) { 89 char *tmp; 90 91 tmp = xmalloc(5); 92 if (hex0 != 0) { 93 snprintf(tmp, 4, "%x%2x", hex0, hex1); 94 } else { 95 snprintf(tmp, 4, "%x", hex1); 96 } 97 98 return tmp; 99} 100 101void 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]; 105 106 char **environ; 107 int i; 108 109 DIR *procdir, *pcidir; 110 FILE *item; 111 struct dirent *cur_bus, *cur_device; 112 113 procdir = opendir("/proc/bus/pci"); 114 if (procdir == NULL) { 115 ERROR("pci coldplug", "Unable to open procfs PCI interface."); 116 return; 117 } 118 119 while ((cur_bus = readdir(procdir)) != NULL) { 120 if (cur_bus->d_type != DT_DIR) 121 continue; 122 123 if (cur_bus->d_name[0] == '.') 124 continue; 125 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); 129 130 while ((cur_device = readdir(pcidir)) != NULL) { 131 if (cur_device->d_type != DT_REG) 132 continue; 133 134 if (cur_device->d_name[0] == '.') 135 continue; 136 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"); 140 141 if (item == NULL) { 142 ERROR("pci coldplug", "Missing PCI entry."); 143 continue; 144 } 145 146 fread(pci_desc_info, 256, 1, item); 147 fclose(item); 148 149 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; 159 160 environ[0] = strdup("ACTION=add"); 161 environ[1] = strdup("SUBSYSTEM=pci"); 162 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); 168 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]); 171 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]); 174 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]); 177 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]); 183 184 dispatch_event(netlink_socket, environ); 185 186 for (i = 0; environ[i] != NULL; i++) 187 free(environ[i]); 188 free(environ); 189 } 190 191 closedir(pcidir); 192 } 193 194 closedir(procdir); 195} 196 197void 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]; 201 202 char **environ; 203 char *t1, *t2, *t3; 204 int i; 205 206 DIR *procdir, *usbdir; 207 FILE *item; 208 struct dirent *cur_bus, *cur_device; 209 210 procdir = opendir("/proc/bus/usb"); 211 if (procdir == NULL) { 212 ERROR("usb coldplug", "Unable to open procfs usb interface."); 213 return; 214 } 215 216 while ((cur_bus = readdir(procdir)) != NULL) { 217 if (cur_bus->d_type != DT_DIR) 218 continue; 219 220 if (cur_bus->d_name[0] == '.') 221 continue; 222 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); 226 227 while ((cur_device = readdir(usbdir)) != NULL) { 228 if (cur_device->d_type != DT_REG) 229 continue; 230 231 if (cur_device->d_name[0] == '.') 232 continue; 233 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"); 237 238 if (item == NULL) { 239 ERROR("usb coldplug", "Missing usb entry."); 240 continue; 241 } 242 243 fread(usb_desc_info, 52, 1, item); 244 fclose(item); 245 246 environ = xmalloc(sizeof(char*) * 8); 247 environ[7] = NULL; 248 249 environ[0] = strdup("ACTION=add"); 250 environ[1] = strdup("SUBSYSTEM=usb"); 251 252 environ[2] = xmalloc(8 + strlen(usb_dev_name)); 253 strcpy(environ[2], "DEVICE="); 254 strcat(environ[2], usb_dev_name); 255 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]); 261 262 snprintf(environ[3], 23, "PRODUCT=%s/%s/%s", t1, t2, t3); 263 264 free(t1); free(t2); free(t3); 265 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]); 269 270 environ[5] = xmalloc(55); 271 memset(environ[5], 0, 55); 272 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]); 278 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]); 286 287 environ[6] = NULL; 288 } 289 290 dispatch_event(netlink_socket, environ); 291 292 for (i = 0; environ[i] != NULL; i++) 293 free(environ[i]); 294 free(environ); 295 } 296 297 closedir(usbdir); 298 } 299 300 closedir(procdir); 301} 302 303void 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; 310 311 if (map_file("/proc/bus/isapnp/devices", &isapnpmap)) { 312 ERROR("isapnp coldplug", "Unable to open procfs isapnp interface."); 313 return; 314 } 315 316 nptr = isapnpmap.map; 317 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); 324 325 token = dup_token(nline, &nline, isspace); 326 if (!token) 327 continue; 328 329 if (strlen(token) < 14) { 330 free(token); 331 continue; 332 } 333 334 environ = xmalloc(sizeof(char*) * 4); 335 environ[3] = NULL; 336 337 environ[0] = strdup("ACTION=add"); 338 environ[1] = strdup("SUBSYSTEM=pnp"); 339 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'; 346 } 347 348 dispatch_event(netlink_socket, environ); 349 350 for (i = 0; environ[i] != NULL; i++) 351 free(environ[i]); 352 free(environ); 353 354 free(token); 355 free(line); 356 } 357 358 unmap_file(&isapnpmap); 359} 360 361int main(int argc, char *argv[], char **environ) { 362 int netlink_socket; 363 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; 368 } 369 370 generate_pci_events(netlink_socket); 371 generate_usb_events(netlink_socket); 372 generate_isapnp_events(netlink_socket); 373 374 close(netlink_socket); 375 return 0; 376} 377