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 <string.h> 16#include <errno.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#include <linux/input.h> 27 28#include "mem_utils.h" 29#include "hotplug2.h" 30#include "hotplug2_utils.h" 31#include "parser_utils.h" 32 33#define MODALIAS_MAX_LEN 1024 34 35#ifndef KEY_MIN_INTERESTING 36#define KEY_MIN_INTERESTING KEY_MUTE 37#endif 38 39/* Some kernel headers appear to define it even without __KERNEL__ */ 40#ifndef BITS_PER_LONG 41#define BITS_PER_LONG (sizeof(long) * 8) 42#endif 43#ifndef NBITS 44#define NBITS(x) ((x / BITS_PER_LONG) + 1) 45#endif 46 47#define TEST_INPUT_BIT(i,bm) (bm[i / BITS_PER_LONG] & (((unsigned long)1) << (i%BITS_PER_LONG))) 48 49/** 50 * Parses a bitmap; output is a list of offsets of bits of a bitmap 51 * of arbitrary size that are set to 1. 52 * 53 * @1 Name of the bitmap parsed 54 * @2 The actual bitmap pointer 55 * @3 Lower boundary of the bitmap 56 * @4 Upper boundary of the bitmap 57 * 58 * Returns: Newly allocated string containing the offsets 59 */ 60char *bitmap_to_bitstring(char name, unsigned long *bm, unsigned int min_bit, unsigned int max_bit) 61{ 62 char *rv; 63 unsigned int i, len = 0, size = 16, srv; 64 65 rv = xmalloc(size); 66 67 len += snprintf(rv + len, size - len, "%c", name); 68 69 for (i = min_bit; i < max_bit; i++) { 70 if (TEST_INPUT_BIT(i, bm)) { 71 while ((srv = snprintf(rv + len, size - len, "%X,", i)) >= (size - len)) { 72 size = size * 2; 73 rv = xrealloc(rv, size); 74 } 75 len += srv; 76 } 77 } 78 79 return rv; 80} 81 82/** 83 * Reverses the bitmap_to_bitstring function. 84 * 85 * @1 Bitstring to be converted 86 * @2 Output bitmap 87 * @3 Size of the whole bitmap 88 * 89 * Returns: void 90 */ 91void string_to_bitmap(char *input, unsigned long *bitmap, int bm_len) { 92 char *token, *ptr; 93 int i = 0; 94 95 ptr = input + strlen(input); 96 97 while ((token = dup_token_r(ptr, input, &ptr, isspace)) != NULL) { 98 bitmap[i] = strtoul(token, NULL, 16); 99 free(token); 100 i++; 101 } 102 103 while (i < bm_len) 104 bitmap[i++] = 0; 105} 106 107#define GET_BITMAP(mapkey, bitmap, name, min) \ 108 if (TEST_INPUT_BIT(EV_ ## mapkey, ev_bits)) { \ 109 token = getenv(#mapkey); \ 110 if (token == NULL) \ 111 return -1; \ 112 \ 113 string_to_bitmap(token, bitmap ## _bits, NBITS(mapkey ## _MAX)); \ 114 } \ 115 bitmap = bitmap_to_bitstring(name, bitmap ## _bits, min, mapkey ## _MAX); 116 117/** 118 * Creates an input modalias out of preset environmental variables. 119 * 120 * @1 Pointer to where modalias will be created 121 * @2 Maximum size of the modalias 122 * 123 * Returns: 0 if success, -1 otherwise 124 */ 125int get_input_modalias(char *modalias, int modalias_len) { 126 char *product_env; 127 char *ptr; 128 char *token; 129 unsigned int bustype, vendor, product, version; 130 131 char *ev, *key, *rel, *abs, *sw, *msc, *led, *snd, *ff; 132 133 unsigned long ev_bits[NBITS(EV_MAX)]; 134 unsigned long key_bits[NBITS(KEY_MAX)]; 135 unsigned long rel_bits[NBITS(REL_MAX)]; 136 unsigned long abs_bits[NBITS(ABS_MAX)]; 137 unsigned long msc_bits[NBITS(MSC_MAX)]; 138 unsigned long led_bits[NBITS(LED_MAX)]; 139 unsigned long snd_bits[NBITS(SND_MAX)]; 140 unsigned long ff_bits[NBITS(FF_MAX)]; 141 142 #if defined(SW_MAX) && defined(EV_SW) 143 unsigned long sw_bits[NBITS(SW_MAX)]; 144 #endif 145 146 memset(ev_bits, 0, NBITS(EV_MAX) * sizeof(long)); 147 memset(key_bits, 0, NBITS(KEY_MAX) * sizeof(long)); 148 memset(rel_bits, 0, NBITS(REL_MAX) * sizeof(long)); 149 memset(abs_bits, 0, NBITS(ABS_MAX) * sizeof(long)); 150 memset(msc_bits, 0, NBITS(MSC_MAX) * sizeof(long)); 151 memset(led_bits, 0, NBITS(LED_MAX) * sizeof(long)); 152 memset(snd_bits, 0, NBITS(SND_MAX) * sizeof(long)); 153 memset(ff_bits, 0, NBITS(FF_MAX) * sizeof(long)); 154 #if defined(SW_MAX) && defined(EV_SW) 155 memset(sw_bits, 0, NBITS(SW_MAX) * sizeof(long)); 156 #endif 157 158 product_env = getenv("PRODUCT"); 159 160 if (product_env == NULL) 161 return -1; 162 163 /* PRODUCT */ 164 ptr = strchr(product_env, '/'); 165 if (ptr == NULL || ptr[1] == '\0') 166 return -1; 167 168 bustype = strtoul(product_env, NULL, 16); 169 vendor = strtoul(ptr+1, NULL, 16); 170 ptr = strchr(ptr+1, '/'); 171 if (ptr == NULL || ptr[1] == '\0') 172 return -1; 173 174 product = strtoul(ptr+1, NULL, 16); 175 ptr = strchr(ptr+1, '/'); 176 if (ptr == NULL || ptr[1] == '\0') 177 return -1; 178 179 version = strtoul(ptr+1, NULL, 16); 180 181 /* EV */ 182 token = getenv("EV"); 183 if (token == NULL) 184 return -1; 185 186 string_to_bitmap(token, ev_bits, NBITS(EV_MAX)); 187 188 ev = bitmap_to_bitstring('e', ev_bits, 0, EV_MAX); 189 GET_BITMAP(KEY, key, 'k', KEY_MIN_INTERESTING); 190 GET_BITMAP(REL, rel, 'r', 0); 191 GET_BITMAP(ABS, abs, 'a', 0); 192 GET_BITMAP(MSC, msc, 'm', 0); 193 GET_BITMAP(LED, led, 'l', 0); 194 GET_BITMAP(SND, snd, 's', 0); 195 GET_BITMAP(FF, ff, 'f', 0); 196 #if defined(SW_MAX) && defined(EV_SW) 197 GET_BITMAP(SW, sw, 'w', 0); 198 #else 199 sw=strdup(""); 200 #endif 201 202 snprintf(modalias, modalias_len, 203 "MODALIAS=input:b%04Xv%04Xp%04Xe%04X-" 204 "%s%s%s%s%s%s%s%s%s", 205 bustype, vendor, product, version, 206 ev, key, rel, abs, msc, led, snd, ff, sw); 207 208 /* Ugly but straightforward*/ 209 free(ev); 210 free(key); 211 free(rel); 212 free(abs); 213 free(msc); 214 free(led); 215 free(snd); 216 free(ff); 217 free(sw); 218 219 return 0; 220} 221#undef NBITS 222#undef TEST_INPUT_BIT 223 224/** 225 * Creates a PCI modalias out of preset environmental variables. 226 * 227 * @1 Pointer to where modalias will be created 228 * @2 Maximum size of the modalias 229 * 230 * Returns: 0 if success, -1 otherwise 231 */ 232int get_pci_modalias(char *modalias, int modalias_len) { 233 char *class_env, *id_env, *subsys_env; 234 char *ptr; 235 unsigned long vendor, device, sub_vendor, sub_device, class_type; 236 unsigned char baseclass, subclass, interface; 237 238 id_env = getenv("PCI_ID"); 239 subsys_env = getenv("PCI_SUBSYS_ID"); 240 class_env = getenv("PCI_CLASS"); 241 if (id_env == NULL || subsys_env == NULL || class_env == NULL) 242 return -1; 243 244 if (strlen(id_env) < 9 || strlen(subsys_env) < 9) 245 return -1; 246 247 /* PCI_ID */ 248 ptr = strchr(id_env, ':'); 249 if (ptr == NULL || ptr[1] == '\0') 250 return -1; 251 252 vendor = strtoul(id_env, NULL, 16); 253 device = strtoul(ptr+1, NULL, 16); 254 255 /* PCI_SUBSYS_ID */ 256 ptr = strchr(subsys_env, ':'); 257 if (ptr == NULL || ptr[1] == '\0') 258 return -1; 259 260 sub_vendor = strtoul(id_env, NULL, 16); 261 sub_device = strtoul(ptr+1, NULL, 16); 262 263 /* PCI_CLASS */ 264 class_type = strtoul(class_env, NULL, 16); 265 baseclass = (unsigned char)(class_type >> 16); 266 subclass = (unsigned char)(class_type >> 8); 267 interface = (unsigned char)class_type; 268 269 snprintf(modalias, modalias_len, 270 "MODALIAS=pci:v%08lXd%08lXsv%08lXsd%08lXbc%02Xsc%02Xi%02X", 271 vendor, device, sub_vendor, sub_device, 272 baseclass, subclass, interface); 273 274 return 0; 275} 276 277/** 278 * Creates an IEEE1394 (FireWire) modalias out of preset environmental 279 * variables. 280 * 281 * @1 Pointer to where modalias will be created 282 * @2 Maximum size of the modalias 283 * 284 * Returns: 0 if success, -1 otherwise 285 */ 286int get_ieee1394_modalias(char *modalias, int modalias_len) { 287 char *vendor_env, *model_env; 288 char *specifier_env, *version_env; 289 unsigned long vendor, model; 290 unsigned long specifier, version; 291 292 vendor_env = getenv("VENDOR_ID"); 293 model_env = getenv("MODEL_ID"); 294 specifier_env = getenv("SPECIFIER_ID"); 295 version_env = getenv("VERSION"); 296 297 if (vendor_env == NULL || model_env == NULL || 298 specifier_env == NULL || version_env == NULL) 299 return -1; 300 301 vendor = strtoul(vendor_env, NULL, 16); 302 model = strtoul(model_env, NULL, 16); 303 specifier = strtoul(specifier_env, NULL, 16); 304 version = strtoul(version_env, NULL, 16); 305 306 snprintf(modalias, modalias_len, 307 "MODALIAS=ieee1394:ven%08lXmo%08lXsp%08lXver%08lX", 308 vendor, model, specifier, version); 309 310 return 0; 311} 312 313/** 314 * Creates a serio modalias out of preset environmental variables. 315 * 316 * @1 Pointer to where modalias will be created 317 * @2 Maximum size of the modalias 318 * 319 * Returns: 0 if success, -1 otherwise 320 */ 321int get_serio_modalias(char *modalias, int modalias_len) { 322 char *serio_type_env, *serio_proto_env; 323 char *serio_id_env, *serio_extra_env; 324 unsigned int serio_type, serio_proto; 325 unsigned int serio_specifier, serio_version; 326 327 serio_type_env = getenv("SERIO_TYPE"); 328 serio_proto_env = getenv("SERIO_PROTO"); 329 serio_id_env = getenv("SERIO_ID"); 330 serio_extra_env = getenv("SERIO_EXTRA"); 331 332 if (serio_type_env == NULL || serio_proto_env == NULL || 333 serio_id_env == NULL || serio_extra_env == NULL) 334 return -1; 335 336 serio_type = strtoul(serio_type_env, NULL, 16); 337 serio_proto = strtoul(serio_proto_env, NULL, 16); 338 serio_specifier = strtoul(serio_id_env, NULL, 16); 339 serio_version = strtoul(serio_extra_env, NULL, 16); 340 341 snprintf(modalias, modalias_len, 342 "MODALIAS=serio:ty%02Xpr%02Xid%02Xex%02X", 343 serio_type, serio_proto, serio_specifier, serio_version); 344 345 return 0; 346} 347 348/** 349 * Creates an USB modalias out of preset environmental variables. 350 * 351 * @1 Pointer to where modalias will be created 352 * @2 Maximum size of the modalias 353 * 354 * Returns: 0 if success, -1 otherwise 355 */ 356int get_usb_modalias(char *modalias, int modalias_len) { 357 char *product_env, *type_env, *interface_env; 358 char *ptr; 359 unsigned int idVendor, idProduct, bcdDevice; 360 unsigned int device_class, device_subclass, device_protocol; 361 unsigned int interface_class, interface_subclass, interface_protocol; 362 363 product_env = getenv("PRODUCT"); 364 type_env = getenv("TYPE"); 365 interface_env = getenv("INTERFACE"); 366 367 if (product_env == NULL || type_env == NULL) 368 return -1; 369 370 /* PRODUCT */ 371 ptr = strchr(product_env, '/'); 372 if (ptr == NULL || ptr[1] == '\0') 373 return -1; 374 idVendor = strtoul(product_env, NULL, 16); 375 idProduct = strtoul(ptr+1, NULL, 16); 376 ptr = strchr(ptr+1, '/'); 377 if (ptr == NULL || ptr[1] == '\0') 378 return -1; 379 bcdDevice = strtoul(ptr+1, NULL, 16); 380 381 /* TYPE */ 382 ptr = strchr(type_env, '/'); 383 if (ptr == NULL || ptr[1] == '\0') 384 return -1; 385 device_class = strtoul(type_env, NULL, 10); 386 device_subclass = strtoul(ptr+1, NULL, 10); 387 ptr = strchr(ptr+1, '/'); 388 if (ptr == NULL || ptr[1] == '\0') 389 return -1; 390 device_protocol = strtoul(ptr+1, NULL, 10); 391 392 /* INTERFACE */ 393 if (interface_env != NULL) { 394 ptr = strchr(interface_env, '/'); 395 if (ptr == NULL || ptr[1] == '\0') 396 return -1; 397 interface_class = strtoul(interface_env, NULL, 10); 398 interface_subclass = strtoul(ptr+1, NULL, 10); 399 ptr = strchr(ptr+1, '/'); 400 if (ptr == NULL || ptr[1] == '\0') 401 return -1; 402 interface_protocol = strtoul(ptr+1, NULL, 10); 403 404 snprintf(modalias, modalias_len, 405 "MODALIAS=usb:v%04Xp%04Xd%04X" 406 "dc%02Xdsc%02Xdp%02Xic%02Xisc%02Xip%02X", 407 idVendor, idProduct, bcdDevice, 408 device_class, device_subclass, device_protocol, 409 interface_class, interface_subclass, interface_protocol); 410 } else { 411 snprintf(modalias, modalias_len, 412 "MODALIAS=usb:v%04Xp%04Xd%04X" 413 "dc%02Xdsc%02Xdp%02Xic*isc*ip*", 414 idVendor, idProduct, bcdDevice, 415 device_class, device_subclass, device_protocol); 416 } 417 418 return 0; 419} 420 421/** 422 * Distributes modalias generating according to the bus name. 423 * 424 * @1 Bus name 425 * @2 Pointer to where modalias will be created 426 * @3 Maximum size of the modalias 427 * 428 * Returns: The return value of the subsystem modalias function, or -1 if 429 * no match. 430 */ 431int get_modalias(char *bus, char *modalias, int modalias_len) { 432 memset(modalias, 0, modalias_len); 433 434 if (!strcmp(bus, "pci")) 435 return get_pci_modalias(modalias, modalias_len); 436 437 if (!strcmp(bus, "usb")) 438 return get_usb_modalias(modalias, modalias_len); 439 440 if (!strcmp(bus, "ieee1394")) 441 return get_ieee1394_modalias(modalias, modalias_len); 442 443 if (!strcmp(bus, "serio")) 444 return get_serio_modalias(modalias, modalias_len); 445 446 if (!strcmp(bus, "input")) 447 return get_input_modalias(modalias, modalias_len); 448 449 /* 'ccw' devices do not generate events, we do not need to handle them */ 450 /* 'of' devices do not generate events either */ 451 /* 'pnp' devices do generate events, but they lack any device */ 452 /* description whatsoever. */ 453 454 return -1; 455} 456 457/** 458 * Turns all environmental variables as set when invoked by /proc/sys/hotplug 459 * into an uevent formatted (thus not null-terminated) string. 460 * 461 * @1 All environmental variables 462 * @2 Bus of the event (as read from argv) 463 * @3 Pointer to size of the returned uevent string 464 * 465 * Returns: Not null terminated uevent string. 466 */ 467inline char *get_uevent_string(char **environ, char *bus, unsigned long *uevent_string_len) { 468 char *uevent_string; 469 char *tmp; 470 char modalias[MODALIAS_MAX_LEN]; 471 unsigned long offset; 472 473 tmp = getenv("ACTION"); 474 if (tmp == NULL) 475 return NULL; 476 477 *uevent_string_len = strlen(tmp) + 1; 478 offset = *uevent_string_len - 1; 479 uevent_string = xmalloc(*uevent_string_len); 480 strcpy(uevent_string, tmp); 481 uevent_string[offset] = '@'; 482 offset++; 483 484 for (; *environ != NULL; environ++) { 485 *uevent_string_len += strlen(*environ) + 1; 486 uevent_string = xrealloc(uevent_string, *uevent_string_len); 487 strcpy(&uevent_string[offset], *environ); 488 offset = *uevent_string_len; 489 } 490 491 if (getenv("SEQNUM") == NULL) { 492 /* 64 + 7 ('SEQNUM=') + 1 ('\0') */ 493 tmp = xmalloc(72); 494 memset(tmp, 0, 72); 495 snprintf(tmp, 72, "SEQNUM=%llu", get_kernel_seqnum()); 496 497 *uevent_string_len += strlen(tmp) + 1; 498 uevent_string = xrealloc(uevent_string, *uevent_string_len); 499 strcpy(&uevent_string[offset], tmp); 500 offset = *uevent_string_len; 501 502 free(tmp); 503 } 504 505 if (getenv("SUBSYSTEM") == NULL) { 506 /* 10 ('SUBSYSTEM=') + 1 ('\0') */ 507 tmp = xmalloc(11 + strlen(bus)); 508 strcpy(tmp, "SUBSYSTEM="); 509 strcat(tmp+10, bus); 510 511 *uevent_string_len += strlen(tmp) + 1; 512 uevent_string = xrealloc(uevent_string, *uevent_string_len); 513 strcpy(&uevent_string[offset], tmp); 514 offset = *uevent_string_len; 515 516 free(tmp); 517 } 518 519 /* Only create our own MODALIAS if we do not have one set... */ 520 if (getenv("MODALIAS") == NULL) { 521 if (!get_modalias(bus, modalias, MODALIAS_MAX_LEN)) { 522 *uevent_string_len += strlen(modalias) + 1; 523 uevent_string = xrealloc(uevent_string, *uevent_string_len); 524 strcpy(&uevent_string[offset], modalias); 525 offset = *uevent_string_len; 526 } 527 } 528 529 return uevent_string; 530} 531 532int main(int argc, char *argv[], char **environ) { 533 char *uevent_string; 534 unsigned long uevent_string_len; 535 int netlink_socket; 536 537 if (argv[1] == NULL) { 538 ERROR("parsing arguments", "Malformed event arguments (bus missing)."); 539 return 1; 540 } 541 542 uevent_string = get_uevent_string(environ, argv[1], &uevent_string_len); 543 if (uevent_string == NULL) { 544 ERROR("parsing env vars", "Malformed event environmental variables."); 545 return 1; 546 } 547 548 netlink_socket = init_netlink_socket(NETLINK_CONNECT); 549 if (netlink_socket == -1) { 550 ERROR("netlink init","Unable to open netlink socket."); 551 goto exit; 552 } 553 554 if (send(netlink_socket, uevent_string, uevent_string_len, 0) == -1) { 555 ERROR("sending data","send failed: %s.", strerror(errno)); 556 } 557 close(netlink_socket); 558 559exit: 560 free(uevent_string); 561 562 return 0; 563} 564