loadmod.c revision 706f2543
1/* 2 * Copyright 1995-1998 by Metro Link, Inc. 3 * 4 * Permission to use, copy, modify, distribute, and sell this software and its 5 * documentation for any purpose is hereby granted without fee, provided that 6 * the above copyright notice appear in all copies and that both that 7 * copyright notice and this permission notice appear in supporting 8 * documentation, and that the name of Metro Link, Inc. not be used in 9 * advertising or publicity pertaining to distribution of the software without 10 * specific, written prior permission. Metro Link, Inc. makes no 11 * representations about the suitability of this software for any purpose. 12 * It is provided "as is" without express or implied warranty. 13 * 14 * METRO LINK, INC. DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, 15 * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO 16 * EVENT SHALL METRO LINK, INC. BE LIABLE FOR ANY SPECIAL, INDIRECT OR 17 * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, 18 * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER 19 * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR 20 * PERFORMANCE OF THIS SOFTWARE. 21 */ 22/* 23 * Copyright (c) 1997-2002 by The XFree86 Project, Inc. 24 * 25 * Permission is hereby granted, free of charge, to any person obtaining a 26 * copy of this software and associated documentation files (the "Software"), 27 * to deal in the Software without restriction, including without limitation 28 * the rights to use, copy, modify, merge, publish, distribute, sublicense, 29 * and/or sell copies of the Software, and to permit persons to whom the 30 * Software is furnished to do so, subject to the following conditions: 31 * 32 * The above copyright notice and this permission notice shall be included in 33 * all copies or substantial portions of the Software. 34 * 35 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 36 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 37 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 38 * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR 39 * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, 40 * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR 41 * OTHER DEALINGS IN THE SOFTWARE. 42 * 43 * Except as contained in this notice, the name of the copyright holder(s) 44 * and author(s) shall not be used in advertising or otherwise to promote 45 * the sale, use or other dealings in this Software without prior written 46 * authorization from the copyright holder(s) and author(s). 47 */ 48 49#ifdef HAVE_XORG_CONFIG_H 50#include <xorg-config.h> 51#endif 52 53#include "os.h" 54/* For stat() and related stuff */ 55#define NO_OSLIB_PROTOTYPES 56#include "xf86_OSlib.h" 57#define LOADERDECLARATIONS 58#include "loaderProcs.h" 59#include "misc.h" 60#include "xf86.h" 61#include "xf86Priv.h" 62#include "xf86Xinput.h" 63#include "loader.h" 64#include "xf86Optrec.h" 65 66#include <sys/types.h> 67#include <regex.h> 68#include <dirent.h> 69#include <limits.h> 70 71typedef struct _pattern { 72 const char *pattern; 73 regex_t rex; 74} PatternRec, *PatternPtr; 75 76/* Prototypes for static functions */ 77static char *FindModule(const char *, const char *, const char **, 78 PatternPtr); 79static Bool CheckVersion(const char *, XF86ModuleVersionInfo *, 80 const XF86ModReqInfo *); 81static void UnloadModuleOrDriver(ModuleDescPtr mod); 82static char *LoaderGetCanonicalName(const char *, PatternPtr); 83static void RemoveChild(ModuleDescPtr); 84static ModuleDescPtr doLoadModule(const char *, const char *, const char **, 85 const char **, pointer, 86 const XF86ModReqInfo *, int *, int *); 87 88const ModuleVersions LoaderVersionInfo = { 89 XORG_VERSION_CURRENT, 90 ABI_ANSIC_VERSION, 91 ABI_VIDEODRV_VERSION, 92 ABI_XINPUT_VERSION, 93 ABI_EXTENSION_VERSION, 94 ABI_FONT_VERSION 95}; 96 97static void 98FreeStringList(char **paths) 99{ 100 char **p; 101 102 if (!paths) 103 return; 104 105 for (p = paths; *p; p++) 106 free(*p); 107 108 free(paths); 109} 110 111static char **defaultPathList = NULL; 112 113static Bool 114PathIsAbsolute(const char *path) 115{ 116 return *path == '/'; 117} 118 119/* 120 * Convert a comma-separated path into a NULL-terminated array of path 121 * elements, rejecting any that are not full absolute paths, and appending 122 * a '/' when it isn't already present. 123 */ 124static char ** 125InitPathList(const char *path) 126{ 127 char *fullpath = NULL; 128 char *elem = NULL; 129 char **list = NULL, **save = NULL; 130 int len; 131 int addslash; 132 int n = 0; 133 134 if (!path) 135 return defaultPathList; 136 137 fullpath = strdup(path); 138 if (!fullpath) 139 return NULL; 140 elem = strtok(fullpath, ","); 141 while (elem) { 142 if (PathIsAbsolute(elem)) 143 { 144 len = strlen(elem); 145 addslash = (elem[len - 1] != '/'); 146 if (addslash) 147 len++; 148 save = list; 149 list = realloc(list, (n + 2) * sizeof(char *)); 150 if (!list) { 151 if (save) { 152 save[n] = NULL; 153 FreeStringList(save); 154 } 155 free(fullpath); 156 return NULL; 157 } 158 list[n] = malloc(len + 1); 159 if (!list[n]) { 160 FreeStringList(list); 161 free(fullpath); 162 return NULL; 163 } 164 strcpy(list[n], elem); 165 if (addslash) { 166 list[n][len - 1] = '/'; 167 list[n][len] = '\0'; 168 } 169 n++; 170 } 171 elem = strtok(NULL, ","); 172 } 173 if (list) 174 list[n] = NULL; 175 free(fullpath); 176 return list; 177} 178 179static void 180FreePathList(char **pathlist) 181{ 182 if (pathlist && pathlist != defaultPathList) 183 FreeStringList(pathlist); 184} 185 186void 187LoaderSetPath(const char *path) 188{ 189 if (!path) 190 return; 191 192 defaultPathList = InitPathList(path); 193} 194 195/* Standard set of module subdirectories to search, in order of preference */ 196static const char *stdSubdirs[] = { 197 "", 198 "input/", 199 "drivers/", 200 "multimedia/", 201 "extensions/", 202 "internal/", 203 NULL 204}; 205 206/* 207 * Standard set of module name patterns to check, in order of preference 208 * These are regular expressions (suitable for use with POSIX regex(3)). 209 * 210 * This list assumes that you're an ELFish platform and therefore your 211 * shared libraries are named something.so. If we're ever nuts enough 212 * to port this DDX to, say, Darwin, we'll need to fix this. 213 */ 214static PatternRec stdPatterns[] = { 215 {"^lib(.*)\\.so$",}, 216 {"(.*)_drv\\.so$",}, 217 {"(.*)\\.so$",}, 218 {NULL,} 219}; 220 221static PatternPtr 222InitPatterns(const char **patternlist) 223{ 224 char errmsg[80]; 225 int i, e; 226 PatternPtr patterns = NULL; 227 PatternPtr p = NULL; 228 static int firstTime = 1; 229 const char **s; 230 231 if (firstTime) { 232 /* precompile stdPatterns */ 233 firstTime = 0; 234 for (p = stdPatterns; p->pattern; p++) 235 if ((e = regcomp(&p->rex, p->pattern, REG_EXTENDED)) != 0) { 236 regerror(e, &p->rex, errmsg, sizeof(errmsg)); 237 FatalError("InitPatterns: regcomp error for `%s': %s\n", 238 p->pattern, errmsg); 239 } 240 } 241 242 if (patternlist) { 243 for (i = 0, s = patternlist; *s; i++, s++) 244 if (*s == DEFAULT_LIST) 245 i += sizeof(stdPatterns) / sizeof(stdPatterns[0]) - 1 - 1; 246 patterns = malloc((i + 1) * sizeof(PatternRec)); 247 if (!patterns) { 248 return NULL; 249 } 250 for (i = 0, s = patternlist; *s; i++, s++) 251 if (*s != DEFAULT_LIST) { 252 p = patterns + i; 253 p->pattern = *s; 254 if ((e = regcomp(&p->rex, p->pattern, REG_EXTENDED)) != 0) { 255 regerror(e, &p->rex, errmsg, sizeof(errmsg)); 256 ErrorF("InitPatterns: regcomp error for `%s': %s\n", 257 p->pattern, errmsg); 258 i--; 259 } 260 } else { 261 for (p = stdPatterns; p->pattern; p++, i++) 262 patterns[i] = *p; 263 if (p != stdPatterns) 264 i--; 265 } 266 patterns[i].pattern = NULL; 267 } else 268 patterns = stdPatterns; 269 return patterns; 270} 271 272static void 273FreePatterns(PatternPtr patterns) 274{ 275 if (patterns && patterns != stdPatterns) 276 free(patterns); 277} 278 279static const char ** 280InitSubdirs(const char **subdirlist) 281{ 282 int i; 283 const char **tmp_subdirlist = NULL; 284 char **subdirs = NULL; 285 const char **s, **stmp = NULL; 286 const char *osname; 287 const char *slash; 288 int oslen = 0, len; 289 Bool indefault; 290 291 if (subdirlist == NULL) { 292 subdirlist = tmp_subdirlist = malloc(2 * sizeof(char *)); 293 if (subdirlist == NULL) 294 return NULL; 295 subdirlist[0] = DEFAULT_LIST; 296 subdirlist[1] = NULL; 297 } 298 299 LoaderGetOS(&osname, NULL, NULL, NULL); 300 oslen = strlen(osname); 301 302 { 303 /* Count number of entries and check for invalid paths */ 304 for (i = 0, s = subdirlist; *s; i++, s++) { 305 if (*s == DEFAULT_LIST) { 306 i += sizeof(stdSubdirs) / sizeof(stdSubdirs[0]) - 1 - 1; 307 } else { 308 /* 309 * Path validity check. Don't allow absolute paths, or 310 * paths containing "..". To catch absolute paths on 311 * platforms that use driver letters, don't allow the ':' 312 * character to appear at all. 313 */ 314 if (**s == '/' || **s == '\\' || strchr(*s, ':') || 315 strstr(*s, "..")) { 316 xf86Msg(X_ERROR, "InitSubdirs: Bad subdir: \"%s\"\n", *s); 317 free(tmp_subdirlist); 318 return NULL; 319 } 320 } 321 } 322 subdirs = malloc((i * 2 + 1) * sizeof(char *)); 323 if (!subdirs) { 324 free(tmp_subdirlist); 325 return NULL; 326 } 327 i = 0; 328 s = subdirlist; 329 indefault = FALSE; 330 while (*s) { 331 if (*s == DEFAULT_LIST) { 332 /* Divert to the default list */ 333 indefault = TRUE; 334 stmp = ++s; 335 s = stdSubdirs; 336 } 337 len = strlen(*s); 338 if (**s && (*s)[len - 1] != '/') { 339 slash = "/"; 340 len++; 341 } else 342 slash = ""; 343 len += oslen + 2; 344 if (!(subdirs[i] = malloc(len))) { 345 while (--i >= 0) 346 free(subdirs[i]); 347 free(subdirs); 348 free(tmp_subdirlist); 349 return NULL; 350 } 351 /* tack on the OS name */ 352 sprintf(subdirs[i], "%s%s%s/", *s, slash, osname); 353 i++; 354 /* path as given */ 355 subdirs[i] = strdup(*s); 356 i++; 357 s++; 358 if (indefault && !s) { 359 /* revert back to the main list */ 360 indefault = FALSE; 361 s = stmp; 362 } 363 } 364 subdirs[i] = NULL; 365 } 366 free(tmp_subdirlist); 367 return (const char **)subdirs; 368} 369 370static void 371FreeSubdirs(const char **subdirs) 372{ 373 const char **s; 374 375 if (subdirs) { 376 for (s = subdirs; *s; s++) 377 free((char *)*s); 378 free(subdirs); 379 } 380} 381 382static char * 383FindModuleInSubdir(const char *dirpath, const char *module) 384{ 385 struct dirent *direntry = NULL; 386 DIR *dir = NULL; 387 char *ret = NULL, tmpBuf[PATH_MAX]; 388 struct stat stat_buf; 389 390 dir = opendir(dirpath); 391 if (!dir) 392 return NULL; 393 394 while ((direntry = readdir(dir))) { 395 if (direntry->d_name[0] == '.') 396 continue; 397 snprintf(tmpBuf, PATH_MAX, "%s%s/", dirpath, direntry->d_name); 398 /* the stat with the appended / fails for normal files, 399 and works for sub dirs fine, looks a bit strange in strace 400 but does seem to work */ 401 if ((stat(tmpBuf, &stat_buf) == 0) && S_ISDIR(stat_buf.st_mode)) { 402 if ((ret = FindModuleInSubdir(tmpBuf, module))) 403 break; 404 continue; 405 } 406 407 snprintf(tmpBuf, PATH_MAX, "lib%s.so", module); 408 if (strcmp(direntry->d_name, tmpBuf) == 0) { 409 if (asprintf(&ret, "%s%s", dirpath, tmpBuf) == -1) 410 ret = NULL; 411 break; 412 } 413 414 snprintf(tmpBuf, PATH_MAX, "%s_drv.so", module); 415 if (strcmp(direntry->d_name, tmpBuf) == 0) { 416 if (asprintf(&ret, "%s%s", dirpath, tmpBuf) == -1) 417 ret = NULL; 418 break; 419 } 420 421 snprintf(tmpBuf, PATH_MAX, "%s.so", module); 422 if (strcmp(direntry->d_name, tmpBuf) == 0) { 423 if (asprintf(&ret, "%s%s", dirpath, tmpBuf) == -1) 424 ret = NULL; 425 break; 426 } 427 } 428 429 closedir(dir); 430 return ret; 431} 432 433static char * 434FindModule(const char *module, const char *dirname, const char **subdirlist, 435 PatternPtr patterns) 436{ 437 char buf[PATH_MAX + 1]; 438 char *dirpath = NULL; 439 char *name = NULL; 440 int dirlen; 441 const char **subdirs = NULL; 442 const char **s; 443 444 dirpath = (char *)dirname; 445 if (strlen(dirpath) > PATH_MAX) 446 return NULL; 447 448 subdirs = InitSubdirs(subdirlist); 449 if (!subdirs) 450 return NULL; 451 452 for (s = subdirs; *s; s++) { 453 if ((dirlen = strlen(dirpath) + strlen(*s)) > PATH_MAX) 454 continue; 455 strcpy(buf, dirpath); 456 strcat(buf, *s); 457 if ((name = FindModuleInSubdir(buf, module))) 458 break; 459 } 460 461 FreeSubdirs(subdirs); 462 if (dirpath != dirname) 463 free(dirpath); 464 465 return name; 466} 467 468char ** 469LoaderListDirs(const char **subdirlist, const char **patternlist) 470{ 471 char buf[PATH_MAX + 1]; 472 char **pathlist; 473 char **elem; 474 const char **subdirs; 475 const char **s; 476 PatternPtr patterns; 477 PatternPtr p; 478 DIR *d; 479 struct dirent *dp; 480 regmatch_t match[2]; 481 struct stat stat_buf; 482 int len, dirlen; 483 char *fp; 484 char **listing = NULL; 485 char **save; 486 int n = 0; 487 488 if (!(pathlist = InitPathList(NULL))) 489 return NULL; 490 if (!(subdirs = InitSubdirs(subdirlist))) { 491 FreePathList(pathlist); 492 return NULL; 493 } 494 if (!(patterns = InitPatterns(patternlist))) { 495 FreePathList(pathlist); 496 FreeSubdirs(subdirs); 497 return NULL; 498 } 499 500 for (elem = pathlist; *elem; elem++) { 501 for (s = subdirs; *s; s++) { 502 if ((dirlen = strlen(*elem) + strlen(*s)) > PATH_MAX) 503 continue; 504 strcpy(buf, *elem); 505 strcat(buf, *s); 506 fp = buf + dirlen; 507 if (stat(buf, &stat_buf) == 0 && S_ISDIR(stat_buf.st_mode) && 508 (d = opendir(buf))) { 509 if (buf[dirlen - 1] != '/') { 510 buf[dirlen++] = '/'; 511 fp++; 512 } 513 while ((dp = readdir(d))) { 514 if (dirlen + strlen(dp->d_name) > PATH_MAX) 515 continue; 516 strcpy(fp, dp->d_name); 517 if (!(stat(buf, &stat_buf) == 0 && 518 S_ISREG(stat_buf.st_mode))) 519 continue; 520 for (p = patterns; p->pattern; p++) { 521 if (regexec(&p->rex, dp->d_name, 2, match, 0) == 0 && 522 match[1].rm_so != -1) { 523 len = match[1].rm_eo - match[1].rm_so; 524 save = listing; 525 listing = realloc(listing, 526 (n + 2) * sizeof(char *)); 527 if (!listing) { 528 if (save) { 529 save[n] = NULL; 530 FreeStringList(save); 531 } 532 FreePathList(pathlist); 533 FreeSubdirs(subdirs); 534 FreePatterns(patterns); 535 closedir(d); 536 return NULL; 537 } 538 listing[n] = malloc(len + 1); 539 if (!listing[n]) { 540 FreeStringList(listing); 541 FreePathList(pathlist); 542 FreeSubdirs(subdirs); 543 FreePatterns(patterns); 544 closedir(d); 545 return NULL; 546 } 547 strncpy(listing[n], dp->d_name + match[1].rm_so, 548 len); 549 listing[n][len] = '\0'; 550 n++; 551 break; 552 } 553 } 554 } 555 closedir(d); 556 } 557 } 558 } 559 if (listing) 560 listing[n] = NULL; 561 562 FreePathList(pathlist); 563 FreeSubdirs(subdirs); 564 FreePatterns(patterns); 565 return listing; 566} 567 568void 569LoaderFreeDirList(char **list) 570{ 571 FreeStringList(list); 572} 573 574static Bool 575CheckVersion(const char *module, XF86ModuleVersionInfo * data, 576 const XF86ModReqInfo * req) 577{ 578 int vercode[4]; 579 char verstr[4]; 580 long ver = data->xf86version; 581 MessageType errtype; 582 583 xf86Msg(X_INFO, "Module %s: vendor=\"%s\"\n", 584 data->modname ? data->modname : "UNKNOWN!", 585 data->vendor ? data->vendor : "UNKNOWN!"); 586 587 /* Check for the different scheme used in XFree86 4.0.x releases: 588 * ((((((((major << 7) | minor) << 7) | subminor) << 5) | beta) << 5) | alpha) 589 * Since it wasn't used in 4.1.0 or later, limit to versions in the 4.0.x 590 * range, which limits the overlap with the new version scheme to conflicts 591 * with 6.71.8.764 through 6.72.39.934. 592 */ 593 if ((ver > (4 << 24)) && (ver < ( (4 << 24) + (1 << 17)))) { 594 /* 4.0.x and earlier */ 595 verstr[1] = verstr[3] = 0; 596 verstr[2] = (ver & 0x1f) ? (ver & 0x1f) + 'a' - 1 : 0; 597 ver >>= 5; 598 verstr[0] = (ver & 0x1f) ? (ver & 0x1f) + 'A' - 1 : 0; 599 ver >>= 5; 600 vercode[2] = ver & 0x7f; 601 ver >>= 7; 602 vercode[1] = ver & 0x7f; 603 ver >>= 7; 604 vercode[0] = ver; 605 xf86ErrorF("\tcompiled for %d.%d", vercode[0], vercode[1]); 606 if (vercode[2] != 0) 607 xf86ErrorF(".%d", vercode[2]); 608 xf86ErrorF("%s%s, module version = %d.%d.%d\n", verstr, verstr + 2, 609 data->majorversion, data->minorversion, data->patchlevel); 610 } else { 611 vercode[0] = ver / 10000000; 612 vercode[1] = (ver / 100000) % 100; 613 vercode[2] = (ver / 1000) % 100; 614 vercode[3] = ver % 1000; 615 xf86ErrorF("\tcompiled for %d.%d.%d", vercode[0], vercode[1], 616 vercode[2]); 617 if (vercode[3] != 0) 618 xf86ErrorF(".%d", vercode[3]); 619 xf86ErrorF(", module version = %d.%d.%d\n", data->majorversion, 620 data->minorversion, data->patchlevel); 621 } 622 623 if (data->moduleclass) 624 xf86ErrorFVerb(2, "\tModule class: %s\n", data->moduleclass); 625 626 ver = -1; 627 if (data->abiclass) { 628 int abimaj, abimin; 629 int vermaj, vermin; 630 631 if (!strcmp(data->abiclass, ABI_CLASS_ANSIC)) 632 ver = LoaderVersionInfo.ansicVersion; 633 else if (!strcmp(data->abiclass, ABI_CLASS_VIDEODRV)) 634 ver = LoaderVersionInfo.videodrvVersion; 635 else if (!strcmp(data->abiclass, ABI_CLASS_XINPUT)) 636 ver = LoaderVersionInfo.xinputVersion; 637 else if (!strcmp(data->abiclass, ABI_CLASS_EXTENSION)) 638 ver = LoaderVersionInfo.extensionVersion; 639 else if (!strcmp(data->abiclass, ABI_CLASS_FONT)) 640 ver = LoaderVersionInfo.fontVersion; 641 642 abimaj = GET_ABI_MAJOR(data->abiversion); 643 abimin = GET_ABI_MINOR(data->abiversion); 644 xf86ErrorFVerb(2, "\tABI class: %s, version %d.%d\n", 645 data->abiclass, abimaj, abimin); 646 if (ver != -1) { 647 vermaj = GET_ABI_MAJOR(ver); 648 vermin = GET_ABI_MINOR(ver); 649 if (abimaj != vermaj) { 650 if (LoaderOptions & LDR_OPT_ABI_MISMATCH_NONFATAL) 651 errtype = X_WARNING; 652 else 653 errtype = X_ERROR; 654 xf86MsgVerb(errtype, 0, 655 "module ABI major version (%d) doesn't" 656 " match the server's version (%d)\n", 657 abimaj, vermaj); 658 if (!(LoaderOptions & LDR_OPT_ABI_MISMATCH_NONFATAL)) 659 return FALSE; 660 } else if (abimin > vermin) { 661 if (LoaderOptions & LDR_OPT_ABI_MISMATCH_NONFATAL) 662 errtype = X_WARNING; 663 else 664 errtype = X_ERROR; 665 xf86MsgVerb(errtype, 0, 666 "module ABI minor version (%d) is " 667 "newer than the server's version " 668 "(%d)\n", abimin, vermin); 669 if (!(LoaderOptions & LDR_OPT_ABI_MISMATCH_NONFATAL)) 670 return FALSE; 671 } 672 } 673 } 674 675 /* Check against requirements that the caller has specified */ 676 if (req) { 677 if (req->majorversion != MAJOR_UNSPEC) { 678 if (data->majorversion != req->majorversion) { 679 xf86MsgVerb(X_WARNING, 2, "module major version (%d) " 680 "doesn't match required major version (%d)\n", 681 data->majorversion, req->majorversion); 682 return FALSE; 683 } else if (req->minorversion != MINOR_UNSPEC) { 684 if (data->minorversion < req->minorversion) { 685 xf86MsgVerb(X_WARNING, 2, "module minor version (%d) " 686 "is less than the required minor version (%d)\n", 687 data->minorversion, req->minorversion); 688 return FALSE; 689 } else if (data->minorversion == req->minorversion && 690 req->patchlevel != PATCH_UNSPEC) { 691 if (data->patchlevel < req->patchlevel) { 692 xf86MsgVerb(X_WARNING, 2, "module patch level (%d) " 693 "is less than the required patch level (%d)\n", 694 data->patchlevel, req->patchlevel); 695 return FALSE; 696 } 697 } 698 } 699 } 700 if (req->moduleclass) { 701 if (!data->moduleclass || 702 strcmp(req->moduleclass, data->moduleclass)) { 703 xf86MsgVerb(X_WARNING, 2, "Module class (%s) doesn't match " 704 "the required class (%s)\n", 705 data->moduleclass ? data->moduleclass : "<NONE>", 706 req->moduleclass); 707 return FALSE; 708 } 709 } else if (req->abiclass != ABI_CLASS_NONE) { 710 if (!data->abiclass || strcmp(req->abiclass, data->abiclass)) { 711 xf86MsgVerb(X_WARNING, 2, "ABI class (%s) doesn't match the " 712 "required ABI class (%s)\n", 713 data->abiclass ? data->abiclass : "<NONE>", 714 req->abiclass); 715 return FALSE; 716 } 717 } 718 if ((req->abiclass != ABI_CLASS_NONE) && 719 req->abiversion != ABI_VERS_UNSPEC) { 720 int reqmaj, reqmin, maj, min; 721 722 reqmaj = GET_ABI_MAJOR(req->abiversion); 723 reqmin = GET_ABI_MINOR(req->abiversion); 724 maj = GET_ABI_MAJOR(data->abiversion); 725 min = GET_ABI_MINOR(data->abiversion); 726 if (maj != reqmaj) { 727 xf86MsgVerb(X_WARNING, 2, "ABI major version (%d) doesn't " 728 "match the required ABI major version (%d)\n", 729 maj, reqmaj); 730 return FALSE; 731 } 732 /* XXX Maybe this should be the other way around? */ 733 if (min > reqmin) { 734 xf86MsgVerb(X_WARNING, 2, "module ABI minor version (%d) " 735 "is newer than that available (%d)\n", min, reqmin); 736 return FALSE; 737 } 738 } 739 } 740 return TRUE; 741} 742 743static ModuleDescPtr 744AddSibling(ModuleDescPtr head, ModuleDescPtr new) 745{ 746 new->sib = head; 747 return new; 748} 749 750pointer 751LoadSubModule(pointer _parent, const char *module, 752 const char **subdirlist, const char **patternlist, 753 pointer options, const XF86ModReqInfo * modreq, 754 int *errmaj, int *errmin) 755{ 756 ModuleDescPtr submod; 757 ModuleDescPtr parent = (ModuleDescPtr)_parent; 758 759 xf86MsgVerb(X_INFO, 3, "Loading sub module \"%s\"\n", module); 760 761 if (PathIsAbsolute(module)) { 762 xf86Msg(X_ERROR, 763 "LoadSubModule: Absolute module path not permitted: \"%s\"\n", 764 module); 765 if (errmaj) 766 *errmaj = LDR_BADUSAGE; 767 if (errmin) 768 *errmin = 0; 769 return NULL; 770 } 771 772 submod = doLoadModule(module, NULL, subdirlist, patternlist, options, 773 modreq, errmaj, errmin); 774 if (submod && submod != (ModuleDescPtr) 1) { 775 parent->child = AddSibling(parent->child, submod); 776 submod->parent = parent; 777 } 778 return submod; 779} 780 781static ModuleDescPtr 782NewModuleDesc(const char *name) 783{ 784 ModuleDescPtr mdp = calloc(1, sizeof(ModuleDesc)); 785 786 if (mdp) 787 mdp->name = xstrdup(name); 788 789 return mdp; 790} 791 792ModuleDescPtr 793DuplicateModule(ModuleDescPtr mod, ModuleDescPtr parent) 794{ 795 ModuleDescPtr ret; 796 int errmaj, errmin; 797 798 if (!mod) 799 return NULL; 800 801 ret = NewModuleDesc(mod->name); 802 if (ret == NULL) 803 return NULL; 804 805 if (!(ret->handle = LoaderOpen(mod->path, &errmaj, &errmin))) { 806 free(ret); 807 return NULL; 808 } 809 810 ret->SetupProc = mod->SetupProc; 811 ret->TearDownProc = mod->TearDownProc; 812 ret->TearDownData = NULL; 813 ret->child = DuplicateModule(mod->child, ret); 814 ret->sib = DuplicateModule(mod->sib, parent); 815 ret->parent = parent; 816 ret->VersionInfo = mod->VersionInfo; 817 ret->path = strdup(mod->path); 818 819 return ret; 820} 821 822static const char *compiled_in_modules[] = { 823 "ddc", 824 "i2c", 825 "ramdac", 826 NULL 827}; 828 829static ModuleDescPtr 830doLoadModule(const char *module, const char *path, const char **subdirlist, 831 const char **patternlist, pointer options, 832 const XF86ModReqInfo * modreq, 833 int *errmaj, int *errmin) 834{ 835 XF86ModuleData *initdata = NULL; 836 char **pathlist = NULL; 837 char *found = NULL; 838 char *name = NULL; 839 char **path_elem = NULL; 840 char *p = NULL; 841 ModuleDescPtr ret = NULL; 842 PatternPtr patterns = NULL; 843 int noncanonical = 0; 844 char *m = NULL; 845 const char **cim; 846 847 xf86MsgVerb(X_INFO, 3, "LoadModule: \"%s\"", module); 848 849 patterns = InitPatterns(patternlist); 850 name = LoaderGetCanonicalName(module, patterns); 851 noncanonical = (name && strcmp(module, name) != 0); 852 if (noncanonical) { 853 xf86ErrorFVerb(3, " (%s)\n", name); 854 xf86MsgVerb(X_WARNING, 1, 855 "LoadModule: given non-canonical module name \"%s\"\n", 856 module); 857 m = name; 858 } else { 859 xf86ErrorFVerb(3, "\n"); 860 m = (char *)module; 861 } 862 863 for (cim = compiled_in_modules; *cim; cim++) 864 if (!strcmp (m, *cim)) 865 { 866 xf86MsgVerb(X_INFO, 3, "Module \"%s\" already built-in\n", m); 867 ret = (ModuleDescPtr) 1; 868 goto LoadModule_exit; 869 } 870 871 if (!name) { 872 if (errmaj) 873 *errmaj = LDR_BADUSAGE; 874 if (errmin) 875 *errmin = 0; 876 goto LoadModule_fail; 877 } 878 ret = NewModuleDesc(name); 879 if (!ret) { 880 if (errmaj) 881 *errmaj = LDR_NOMEM; 882 if (errmin) 883 *errmin = 0; 884 goto LoadModule_fail; 885 } 886 887 pathlist = InitPathList(path); 888 if (!pathlist) { 889 /* This could be a malloc failure too */ 890 if (errmaj) 891 *errmaj = LDR_BADUSAGE; 892 if (errmin) 893 *errmin = 1; 894 goto LoadModule_fail; 895 } 896 897 /* 898 * if the module name is not a full pathname, we need to 899 * check the elements in the path 900 */ 901 if (PathIsAbsolute(module)) 902 found = xstrdup(module); 903 path_elem = pathlist; 904 while (!found && *path_elem != NULL) { 905 found = FindModule(m, *path_elem, subdirlist, patterns); 906 path_elem++; 907 /* 908 * When the module name isn't the canonical name, search for the 909 * former if no match was found for the latter. 910 */ 911 if (!*path_elem && m == name) { 912 path_elem = pathlist; 913 m = (char *)module; 914 } 915 } 916 917 /* 918 * did we find the module? 919 */ 920 if (!found) { 921 xf86Msg(X_WARNING, "Warning, couldn't open module %s\n", module); 922 if (errmaj) 923 *errmaj = LDR_NOENT; 924 if (errmin) 925 *errmin = 0; 926 goto LoadModule_fail; 927 } 928 ret->handle = LoaderOpen(found, errmaj, errmin); 929 if (ret->handle == NULL) 930 goto LoadModule_fail; 931 ret->path = strdup(found); 932 933 /* drop any explicit suffix from the module name */ 934 p = strchr(name, '.'); 935 if (p) 936 *p = '\0'; 937 938 /* 939 * now check if the special data object <modulename>ModuleData is 940 * present. 941 */ 942 if (asprintf(&p, "%sModuleData", name) == -1) { 943 p = NULL; 944 if (errmaj) 945 *errmaj = LDR_NOMEM; 946 if (errmin) 947 *errmin = 0; 948 goto LoadModule_fail; 949 } 950 initdata = LoaderSymbol(p); 951 if (initdata) { 952 ModuleSetupProc setup; 953 ModuleTearDownProc teardown; 954 XF86ModuleVersionInfo *vers; 955 956 vers = initdata->vers; 957 setup = initdata->setup; 958 teardown = initdata->teardown; 959 960 if (vers) { 961 if (!CheckVersion(module, vers, modreq)) { 962 if (errmaj) 963 *errmaj = LDR_MISMATCH; 964 if (errmin) 965 *errmin = 0; 966 goto LoadModule_fail; 967 } 968 } else { 969 xf86Msg(X_ERROR, 970 "LoadModule: Module %s does not supply" 971 " version information\n", module); 972 if (errmaj) 973 *errmaj = LDR_INVALID; 974 if (errmin) 975 *errmin = 0; 976 goto LoadModule_fail; 977 } 978 if (setup) 979 ret->SetupProc = setup; 980 if (teardown) 981 ret->TearDownProc = teardown; 982 ret->VersionInfo = vers; 983 } else { 984 /* No initdata is OK for external modules */ 985 if (options == EXTERN_MODULE) 986 goto LoadModule_exit; 987 988 /* no initdata, fail the load */ 989 xf86Msg(X_ERROR, "LoadModule: Module %s does not have a %s " 990 "data object.\n", module, p); 991 if (errmaj) 992 *errmaj = LDR_INVALID; 993 if (errmin) 994 *errmin = 0; 995 goto LoadModule_fail; 996 } 997 if (ret->SetupProc) { 998 ret->TearDownData = ret->SetupProc(ret, options, errmaj, errmin); 999 if (!ret->TearDownData) { 1000 goto LoadModule_fail; 1001 } 1002 } else if (options) { 1003 xf86Msg(X_WARNING, "Module Options present, but no SetupProc " 1004 "available for %s\n", module); 1005 } 1006 goto LoadModule_exit; 1007 1008 LoadModule_fail: 1009 UnloadModule(ret); 1010 ret = NULL; 1011 1012 LoadModule_exit: 1013 FreePathList(pathlist); 1014 FreePatterns(patterns); 1015 free(found); 1016 free(name); 1017 free(p); 1018 1019 return ret; 1020} 1021 1022/* 1023 * LoadModule: load a module 1024 * 1025 * module The module name. Normally this is not a filename but the 1026 * module's "canonical name. A full pathname is, however, 1027 * also accepted. 1028 * path A comma separated list of module directories. 1029 * subdirlist A NULL terminated list of subdirectories to search. When 1030 * NULL, the default "stdSubdirs" list is used. The default 1031 * list is also substituted for entries with value DEFAULT_LIST. 1032 * patternlist A NULL terminated list of regular expressions used to find 1033 * module filenames. Each regex should contain exactly one 1034 * subexpression that corresponds to the canonical module name. 1035 * When NULL, the default "stdPatterns" list is used. The 1036 * default list is also substituted for entries with value 1037 * DEFAULT_LIST. 1038 * options A NULL terminated list of Options that are passed to the 1039 * module's SetupProc function. 1040 * modreq An optional XF86ModReqInfo* containing 1041 * version/ABI/vendor-ABI requirements to check for when 1042 * loading the module. The following fields of the 1043 * XF86ModReqInfo struct are checked: 1044 * majorversion - must match the module's majorversion exactly 1045 * minorversion - the module's minorversion must be >= this 1046 * patchlevel - the module's minorversion.patchlevel must be 1047 * >= this. Patchlevel is ignored when 1048 * minorversion is not set. 1049 * abiclass - (string) must match the module's abiclass 1050 * abiversion - must be consistent with the module's 1051 * abiversion (major equal, minor no older) 1052 * moduleclass - string must match the module's moduleclass 1053 * string 1054 * "don't care" values are ~0 for numbers, and NULL for strings 1055 * errmaj Major error return. 1056 * errmin Minor error return. 1057 * 1058 */ 1059ModuleDescPtr 1060LoadModule(const char *module, const char *path, const char **subdirlist, 1061 const char **patternlist, pointer options, 1062 const XF86ModReqInfo * modreq, int *errmaj, int *errmin) 1063{ 1064 return doLoadModule(module, path, subdirlist, patternlist, options, 1065 modreq, errmaj, errmin); 1066} 1067 1068void 1069UnloadModule(pointer mod) 1070{ 1071 UnloadModuleOrDriver((ModuleDescPtr)mod); 1072} 1073 1074static void 1075UnloadModuleOrDriver(ModuleDescPtr mod) 1076{ 1077 if (mod == (ModuleDescPtr) 1) 1078 return; 1079 1080 if (mod == NULL || mod->name == NULL) 1081 return; 1082 1083 xf86MsgVerb(X_INFO, 3, "UnloadModule: \"%s\"\n", mod->name); 1084 1085 if ((mod->TearDownProc) && (mod->TearDownData)) 1086 mod->TearDownProc(mod->TearDownData); 1087 LoaderUnload(mod->name, mod->handle); 1088 1089 if (mod->child) 1090 UnloadModuleOrDriver(mod->child); 1091 if (mod->sib) 1092 UnloadModuleOrDriver(mod->sib); 1093 free(mod->path); 1094 free(mod->name); 1095 free(mod); 1096} 1097 1098void 1099UnloadSubModule(pointer _mod) 1100{ 1101 ModuleDescPtr mod = (ModuleDescPtr)_mod; 1102 1103 if (mod == NULL || mod->name == NULL) 1104 return; 1105 1106 xf86MsgVerb(X_INFO, 3, "UnloadSubModule: \"%s\"\n", mod->name); 1107 1108 if ((mod->TearDownProc) && (mod->TearDownData)) 1109 mod->TearDownProc(mod->TearDownData); 1110 LoaderUnload(mod->name, mod->handle); 1111 1112 RemoveChild(mod); 1113 1114 if (mod->child) 1115 UnloadModuleOrDriver(mod->child); 1116 1117 free(mod->path); 1118 free(mod->name); 1119 free(mod); 1120} 1121 1122static void 1123RemoveChild(ModuleDescPtr child) 1124{ 1125 ModuleDescPtr mdp; 1126 ModuleDescPtr prevsib; 1127 ModuleDescPtr parent; 1128 1129 if (!child->parent) 1130 return; 1131 1132 parent = child->parent; 1133 if (parent->child == child) { 1134 parent->child = child->sib; 1135 return; 1136 } 1137 1138 prevsib = parent->child; 1139 mdp = prevsib->sib; 1140 while (mdp && mdp != child) { 1141 prevsib = mdp; 1142 mdp = mdp->sib; 1143 } 1144 if (mdp == child) 1145 prevsib->sib = child->sib; 1146 return; 1147} 1148 1149void 1150LoaderErrorMsg(const char *name, const char *modname, int errmaj, int errmin) 1151{ 1152 const char *msg; 1153 MessageType type = X_ERROR; 1154 1155 switch (errmaj) { 1156 case LDR_NOERROR: 1157 msg = "no error"; 1158 break; 1159 case LDR_NOMEM: 1160 msg = "out of memory"; 1161 break; 1162 case LDR_NOENT: 1163 msg = "module does not exist"; 1164 break; 1165 case LDR_NOSUBENT: 1166 msg = "a required submodule could not be loaded"; 1167 break; 1168 case LDR_NOSPACE: 1169 msg = "too many modules"; 1170 break; 1171 case LDR_NOMODOPEN: 1172 msg = "open failed"; 1173 break; 1174 case LDR_UNKTYPE: 1175 msg = "unknown module type"; 1176 break; 1177 case LDR_NOLOAD: 1178 msg = "loader failed"; 1179 break; 1180 case LDR_ONCEONLY: 1181 msg = "already loaded"; 1182 type = X_INFO; 1183 break; 1184 case LDR_NOPORTOPEN: 1185 msg = "port open failed"; 1186 break; 1187 case LDR_NOHARDWARE: 1188 msg = "no hardware found"; 1189 break; 1190 case LDR_MISMATCH: 1191 msg = "module requirement mismatch"; 1192 break; 1193 case LDR_BADUSAGE: 1194 msg = "invalid argument(s) to LoadModule()"; 1195 break; 1196 case LDR_INVALID: 1197 msg = "invalid module"; 1198 break; 1199 case LDR_BADOS: 1200 msg = "module doesn't support this OS"; 1201 break; 1202 case LDR_MODSPECIFIC: 1203 msg = "module-specific error"; 1204 break; 1205 default: 1206 msg = "unknown error"; 1207 } 1208 if (name) 1209 xf86Msg(type, "%s: Failed to load module \"%s\" (%s, %d)\n", 1210 name, modname, msg, errmin); 1211 else 1212 xf86Msg(type, "Failed to load module \"%s\" (%s, %d)\n", 1213 modname, msg, errmin); 1214} 1215 1216/* Given a module path or file name, return the module's canonical name */ 1217static char * 1218LoaderGetCanonicalName(const char *modname, PatternPtr patterns) 1219{ 1220 char *str; 1221 const char *s; 1222 int len; 1223 PatternPtr p; 1224 regmatch_t match[2]; 1225 1226 /* Strip off any leading path */ 1227 s = strrchr(modname, '/'); 1228 if (s == NULL) 1229 s = modname; 1230 else 1231 s++; 1232 1233 /* Find the first regex that is matched */ 1234 for (p = patterns; p->pattern; p++) 1235 if (regexec(&p->rex, s, 2, match, 0) == 0 && match[1].rm_so != -1) { 1236 len = match[1].rm_eo - match[1].rm_so; 1237 str = malloc(len + 1); 1238 if (!str) 1239 return NULL; 1240 strncpy(str, s + match[1].rm_so, len); 1241 str[len] = '\0'; 1242 return str; 1243 } 1244 1245 /* If there is no match, return the whole name minus the leading path */ 1246 return strdup(s); 1247} 1248 1249/* 1250 * Return the module version information. 1251 */ 1252unsigned long 1253LoaderGetModuleVersion(ModuleDescPtr mod) 1254{ 1255 if (!mod || mod == (ModuleDescPtr) 1 || !mod->VersionInfo) 1256 return 0; 1257 1258 return MODULE_VERSION_NUMERIC(mod->VersionInfo->majorversion, 1259 mod->VersionInfo->minorversion, 1260 mod->VersionInfo->patchlevel); 1261} 1262