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